把問題抽象成圖論應該不難(也許都不用抽象?),但是怎麼建邊怎麼跑就千差萬別了。
首先應該注意到的一點是座標的範圍是0~500,也就是501*501個位置,所以陣列/佇列不要開小。
另外題目給出的莉露露沒說位置不能重複,所以每個點可能不止入隊一次,仍然要注意陣列大小。
剛開始一直在想複雜度與n掛鉤的演算法,但是它掛了。
可以發現,n與x*y的差距並不打,所以如果正解複雜度可接受n的話那麼拿xy作為複雜度應該沒有問題。
先大概講一下考場上的暴力(80分,因為上面說的鍋,把陣列開大是88分):
考慮每個莉露露的行動:去乙個位置,撿起由岐,走幾步,扔出去。
如果我們要對於每乙個格仔進行轉移而不是針對每乙個莉露露的話,去乙個位置撿起由岐這個操作就可以變成:
找到最近的莉露露來這個位置,再讓這個莉露露去走,扔。
走和扔的話就能比較簡單的轉移了。
那麼首先的乙個問題是,怎麼找到離每乙個點最近的莉露露有多遠?
所有的二維幾何題都可以用kd-tree亂搞。貌似的確可以這也是我考場上打了一半的思路。
但是這其實就是乙個bfs,以每乙個莉露露為源點不斷擴散直至每個點都會被搜尋到一次。
複雜度o(xy)。可以考慮建乙個超級源點其距離值為-1,由它連向每乙個莉露露,當然也可以直接搞。
然後假如我們已經找到了這個陣列叫nst吧,那麼怎麼跑最短路?
我們假設由岐始終沒著地:在被扔之前另乙個莉露露已經到了落點去準備接住了。(當然不會影響答案)
那麼她就始終在莉露露的手裡了,所有的莉露露只有兩種操作。
1.走一步,費用c,那麼就想四周連邊(不用真的建邊直接for列舉就行)。連4條邊。
2.扔。目的地只能是本行或本列上的,還是列舉,連了x+y條邊。
而因為我們假設不讓由岐落地,所以在到了目的地之後還要讓最近的莉露露來接住她,費用就是ax+b+c*nst[tx][ty]
所以總邊數是x3級別的,複雜度也是。
另外還可以優化一下,如果你是被從這一列扔過來的,那麼你不會再被扔到這一列,行同理,開乙個bool陣列更新最小距離時記錄就好。
這樣的話邊數能減少一些,具體多少看測試點,反正效果還可以。
1 #include2 #include3 #include4 #include5view codeusing
namespace
std;
6const
int xx=,yy=;
7#define tx qx[h]+xx[i]
8#define ty qy[h]+yy[i]
9struct ps};
10 priority_queueq;
11bool l[505][505],r[505][505
];12
int com,nst[505][505],x,y,n,qx[500155],qy[500155
],gx,gy,sx,sy;
13long
long a,b,c,dt[505][505
];14 signed main());
23while(!q.empty())
27#define kx x+xx[i]
28#define ky y+yy[i]
29for(int i=0;i<=3;++i)if(kx>=0&&kx<=x&&ky<=y&&ky>=0&&dt[kx][ky]>d+c)
30 l[kx][ky]=r[kx][ky]=0,q.push((ps));
31if(!l[x][y])for(int i=0;iif(dt[i][y]>d+a*(x-i)+b+c*nst[i][y])
32 l[i][y]=1,r[i][y]=0,q.push((ps));
33if(!l[x][y])for(int i=x+1;i<=x;++i)if(dt[i][y]>d+a*(i-x)+b+c*nst[i][y])
34 l[i][y]=1,r[i][y]=0,q.push((ps));
35if(!r[x][y])for(int i=0;iif(dt[x][i]>d+a*(y-i)+b+c*nst[x][i])
36 r[x][i]=1,l[x][i]=0,q.push((ps));
37if(!r[x][y])for(int i=y+1;i<=y;++i)if(dt[x][i]>d+a*(i-y)+b+c*nst[x][i])
38 r[x][i]=1,l[x][i]=0,q.push((ps));39}
40 }
100%演算法就是稍微優化了一下建邊。
稍微改變狀態定義,其實每次被扔出去可以被分為兩個階段,從那個ax+b能yy一下。
首先花費b的費用起飛,然後沿著乙個方向飛,每飛乙個格仔的費用是a,著陸的費用就是最近的莉露露撿起她的費用c×nst。
當然也可以不飛,一步一步走,這裡和暴力是一樣的。
那麼因為被扔的操作每次也只會向上下左右四個格仔轉移了,所以複雜度有了保證。
然而你現在需要弄清楚她有沒有起飛有沒有著陸,如果在飛的話她是在橫著飛還是豎著。
拆點,拆成3個,分別表示0在地上,1在橫著飛,2在豎著飛。
可以從0轉移到1和2,費用為b。
可以從1,2轉移到0,費用為c×nst。
可以從0轉移到相鄰4個格仔的0,費用為c。
可以從1轉移到左右兩個格仔的1,費用為a。
可以從2轉移到上下兩個格仔的2,費用為a。
總邊數10n2。跑dijkstra,複雜度乘個log,問題不大。
據secret測試可以暴力把所有邊都建出來也能a,但是不推薦大常數者使用。
1 #include2 #include3 #include4 #include5 #include6**複雜度不大,1.5kusing
namespace
std;
7const
int xx=,yy=;
8#define tx qx[h]+xx[i]
9#define ty qy[h]+yy[i]
10struct ps};
11 priority_queueq;
12int com,x,y,n,qx[500155],qy[500155
],gx,gy,sx,sy;
13long
long a,b,c,dt[3][505][505],nst[505][505
];14 signed main());
23while(!q.empty())
27#define kx x+xx[i]
28#define ky y+yy[i]
29if(!st));
32for(int s=1;s<=2;++s)if(dt[s][x][y]>d+b)
33 q.push((ps));
34 }else
);37
if(dt[0][x][y]>d+nst[x][y])q.push((ps));38}
39}40 }
拆點最短路 新板子get
傳送門 timelimit 1000ms memorylimit 32768mb 64 bit integer io format i64d problem description 說粗來泥萌可能不信,home w喜歡的公主被魔王抓走了!home w當然是要去救公主的,但是魔塔的結構很複雜,home...
HDU 5521 Meeting 拆點 最短路
題目鏈結 給m個由圖中結點組成的點集,點集中的點兩兩連通且距離為相等的ti。現有兩人分別從1和n點處同時出發嗎,問能否相遇以及相遇的最短時間。很容易想到直接分別以點1和點n為起始點求最短路,再遍歷各個點即可求得最短相遇時間。然而建圖上卻有問題 這個題中的邊是以點集的形式給出,極端情況下可能會出現有1...
HDU 5521 Meeting 拆點 最短路
題目鏈結 給m個由圖中結點組成的點集,點集中的點兩兩連通且距離為相等的ti。現有兩人分別從1和n點處同時出發嗎,問能否相遇以及相遇的最短時間。很容易想到直接分別以點1和點n為起始點求最短路,再遍歷各個點即可求得最短相遇時間。然而建圖上卻有問題 這個題中的邊是以點集的形式給出,極端情況下可能會出現有1...