【刷題】BZOJ 2069 [POI2004]ZAW
Description
在Byte山的山腳下有一個洞穴入口. 這個洞穴由複雜的洞室經過隧道連線構成. 洞穴的入口是一條筆直通向“前面洞口”的道路. 隧道互相都不交叉(他們只在洞室相遇). 兩個洞室要麼就通過隧道連線起來,要麼就經過若干隧道間接的相連. 現在決定組織辦一個'King's of Byteotia Cup' 比賽. 參賽者的目標就是任意選擇一條路徑進入洞穴並儘快出來即可. 一條路徑必須經過除了“前面洞口”之外還至少要經過其他一個洞室.一條路徑中一個洞不能重複經過(除了“前面洞室”以外),類似的一條隧道也不能重複經過. 一個著名的洞穴探險家 Byteala 正準備參加這個比賽. Byteala 已經訓練了數月而且他已獲得了洞穴系統的一套詳細資料. 對於每條隧道他都詳細計算了從兩個方向經過所需要的時間. 經過一個洞室的時間很短可以忽略不記. 現在Byteala 向計算一條符合條件的最優路徑.
Input
第一行有兩個數n 和 m (3 <= n <= 5000, 3 <= m <= 10000) 分別表示洞室的數目以及連線他們的隧道的數目. 洞室從1 到 n編號. “前面洞室”的編號為1. 接下來m 行描述了所有的隧道. 每行四個整數a,b,c,d 表示從洞室a到洞室b需要c分鐘的時間,而從洞室b到洞室a需要d分鐘的時間, 1 <= a,b <= n, a <> b, 1 <= c,d <= 10000. 你可以假設符合要求的路徑肯定存在.
Output
輸出一行,最少需要多少時間完成比賽.
Sample Input
3 3
1 2 4 3
2 3 4 2
1 3 1 1
Sample Output
6
Solution
這是一個假二進位制分組
對一號點相連的點按照二進位制來分組
列舉二進位制,一種只能由1走向它,另一種只能由它走向1
然後每次都跑一邊Dijkstra就好了
因為任意兩個點一定在一個數的二進位制中在不同的分組,所以方案經過的兩個點一定會被列舉到
#include<bits/stdc++.h> #define ui unsigned int #define ll long long #define db double #define ld long double #define ull unsigned long long #define ft first #define sd second #define pb(a) push_back(a) #define mp(a,b) std::make_pair(a,b) #define ITR(a,b) for(auto a:b) #define REP(a,b,c) for(register int a=(b),a##end=(c);a<=a##end;++a) #define DEP(a,b,c) for(register int a=(b),a##end=(c);a>=a##end;--a) const int MAXN=10000+10,MAXM=200000+10,inf=0x3f3f3f3f; int n,m,e,beg[MAXN],nex[MAXM<<1],to[MAXM<<1],was[MAXM<<1],d[MAXN],dir[MAXN],ans=inf; std::priority_queue< std::pair<int,int>,std::vector< std::pair<int,int> >,std::greater< std::pair<int,int> > > q; namespace IO{ const int Buffsize=1<<15,Output=1<<24; static char Ch[Buffsize],*S=Ch,*T=Ch; inline char getc() { return((S==T)&&(T=(S=Ch)+fread(Ch,1,Buffsize,stdin),S==T)?0:*S++); } static char Out[Output],*nowps=Out; inline void flush(){fwrite(Out,1,nowps-Out,stdout);nowps=Out;} template<typename T>inline void read(T&x) { x=0;static char ch;T f=1; for(ch=getc();!isdigit(ch);ch=getc())if(ch=='-')f=-1; for(;isdigit(ch);ch=getc())x=x*10+(ch-'0'); x*=f; } template<typename T>inline void write(T x,char ch='\n') { if(!x)*nowps++='0'; if(x<0)*nowps++='-',x=-x; static int sta[111],tp; for(tp=0;x;x/=10)sta[++tp]=x%10; for(;tp;*nowps++=sta[tp--]^48); *nowps++=ch; } } using namespace IO; template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);} template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);} template<typename T> inline T min(T x,T y){return x<y?x:y;} template<typename T> inline T max(T x,T y){return x>y?x:y;} inline void insert(int x,int y,int z) { to[++e]=y; nex[e]=beg[x]; beg[x]=e; was[e]=z; } inline void Dijstra(int s) { memset(d,inf,sizeof(d)); d[s]=0; q.push(mp(d[s],s)); while(!q.empty()) { std::pair<int,int> pr=q.top(); q.pop(); if(pr.ft!=d[pr.sd])continue; int x=pr.sd; for(register int i=beg[x];i;i=nex[i]) if(to[i]==1) { if(dir[x])continue; if(d[n+1]>d[x]+was[i])d[n+1]=d[x]+was[i]; } else { if(x==1&&!dir[to[i]])continue; if(d[to[i]]>d[x]+was[i])d[to[i]]=d[x]+was[i],q.push(mp(d[to[i]],to[i])); } } } inline void solve(int ps) { for(register int i=beg[1];i;i=nex[i])dir[to[i]]=(to[i]>>ps)&1; Dijstra(1); chkmin(ans,d[n+1]); for(register int i=beg[1];i;i=nex[i])dir[to[i]]^=1; Dijstra(1); chkmin(ans,d[n+1]); } int main() { read(n);read(m); REP(i,1,m) { int u,v,w1,w2;read(u);read(v);read(w1);read(w2); insert(u,v,w1);insert(v,u,w2); } REP(i,0,13)solve(i); write(ans,'\n');flush(); return 0; }