Escape(狀態壓縮+最大流,好題)
阿新 • • 發佈:2018-11-13
Escape
http://acm.hdu.edu.cn/showproblem.php?pid=3605
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 13201 Accepted Submission(s): 3329
The last line has m digits, the ith digit ai indicates the ith planet can contain ai people most..
0 <= ai <= 100000
If you can output YES, otherwise output NO.
Sample Input 1 1 1 1 2 2 1 0 1 0 1 1
Sample Output YES NO
在TLE n次之後,才反應過來,n太大了。。。
百度之後才知道,需要用類似狀態壓縮的方法
因為m<=10,所以狀態數量只有1000左右,把每個會遇到的狀態數的數量記錄下來,從源點到左邊的點拉容量為a[i]的邊,左邊的點到右邊的點拉容量為INF的邊,右邊的點到匯點拉容量為ci的邊
1 #include<iostream> 2 #include<cstring> 3 #include<string> 4 #include<cmath> 5 #include<cstdio> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<set> 10 #define maxn 200005 11 #define MAXN 200005 12 #define mem(a,b) memset(a,b,sizeof(a)) 13 const int N=200005; 14 const int M=200005; 15 const int INF=0x3f3f3f3f; 16 using namespace std; 17 int n; 18 struct Edge{ 19 int v,next; 20 int cap,flow; 21 }edge[MAXN*20];//注意這裡要開的夠大。。不然WA在這裡真的想罵人。。問題是還不報RE。。 22 int cur[MAXN],pre[MAXN],gap[MAXN],path[MAXN],dep[MAXN]; 23 int cnt=0;//實際儲存總邊數 24 void isap_init() 25 { 26 cnt=0; 27 memset(pre,-1,sizeof(pre)); 28 } 29 void isap_add(int u,int v,int w)//加邊 30 { 31 edge[cnt].v=v; 32 edge[cnt].cap=w; 33 edge[cnt].flow=0; 34 edge[cnt].next=pre[u]; 35 pre[u]=cnt++; 36 } 37 void add(int u,int v,int w){ 38 isap_add(u,v,w); 39 isap_add(v,u,0); 40 } 41 bool bfs(int s,int t)//其實這個bfs可以融合到下面的迭代裡,但是好像是時間要長 42 { 43 memset(dep,-1,sizeof(dep)); 44 memset(gap,0,sizeof(gap)); 45 gap[0]=1; 46 dep[t]=0; 47 queue<int>q; 48 while(!q.empty()) 49 q.pop(); 50 q.push(t);//從匯點開始反向建層次圖 51 while(!q.empty()) 52 { 53 int u=q.front(); 54 q.pop(); 55 for(int i=pre[u];i!=-1;i=edge[i].next) 56 { 57 int v=edge[i].v; 58 if(dep[v]==-1&&edge[i^1].cap>edge[i^1].flow)//注意是從匯點反向bfs,但應該判斷正向弧的餘量 59 { 60 dep[v]=dep[u]+1; 61 gap[dep[v]]++; 62 q.push(v); 63 //if(v==sp)//感覺這兩句優化加了一般沒錯,但是有的題可能會錯,所以還是註釋出來,到時候視情況而定 64 //break; 65 } 66 } 67 } 68 return dep[s]!=-1; 69 } 70 int isap(int s,int t) 71 { 72 if(!bfs(s,t)) 73 return 0; 74 memcpy(cur,pre,sizeof(pre)); 75 //for(int i=1;i<=n;i++) 76 //cout<<"cur "<<cur[i]<<endl; 77 int u=s; 78 path[u]=-1; 79 int ans=0; 80 while(dep[s]<n)//迭代尋找增廣路,n為節點數 81 { 82 if(u==t) 83 { 84 int f=INF; 85 for(int i=path[u];i!=-1;i=path[edge[i^1].v])//修改找到的增廣路 86 f=min(f,edge[i].cap-edge[i].flow); 87 for(int i=path[u];i!=-1;i=path[edge[i^1].v]) 88 { 89 edge[i].flow+=f; 90 edge[i^1].flow-=f; 91 } 92 ans+=f; 93 u=s; 94 continue; 95 } 96 bool flag=false; 97 int v; 98 for(int i=cur[u];i!=-1;i=edge[i].next) 99 { 100 v=edge[i].v; 101 if(dep[v]+1==dep[u]&&edge[i].cap-edge[i].flow) 102 { 103 cur[u]=path[v]=i;//當前弧優化 104 flag=true; 105 break; 106 } 107 } 108 if(flag) 109 { 110 u=v; 111 continue; 112 } 113 int x=n; 114 if(!(--gap[dep[u]]))return ans;//gap優化 115 for(int i=pre[u];i!=-1;i=edge[i].next) 116 { 117 if(edge[i].cap-edge[i].flow&&dep[edge[i].v]<x) 118 { 119 x=dep[edge[i].v]; 120 cur[u]=i;//常數優化 121 } 122 } 123 dep[u]=x+1; 124 gap[dep[u]]++; 125 if(u!=s)//當前點沒有增廣路則後退一個點 126 u=edge[path[u]^1].v; 127 } 128 return ans; 129 } 130 131 int a[maxn]; 132 133 int main(){ 134 int m,s,t; 135 while(~scanf("%d %d",&n,&m)){ 136 int b,c; 137 memset(a,0,sizeof(a)); 138 int Max=0; 139 isap_init(); 140 for(int i=1;i<=n;i++){ 141 int tmp=0; 142 for(int j=1;j<=m;j++){ 143 scanf("%d",&c); 144 tmp=(tmp<<1)|c; 145 } 146 if(Max<tmp) Max=tmp; 147 a[tmp]++; 148 } 149 s=0,t=Max+m+1; 150 for(int i=1;i<=m;i++){ 151 scanf("%d",&c); 152 add(Max+i,t,c); 153 } 154 for(int i=1;i<=Max;i++){ 155 if(a[i]>0){ 156 add(s,i,a[i]); 157 int k=m,p=i; 158 while(k&&p){ 159 int tmp=p%2; 160 p/=2; 161 if(tmp>0) add(i,Max+k,INF); 162 k--; 163 } 164 } 165 } 166 int tmp=n; 167 n=Max+m+2; 168 int ans=isap(s,t); 169 if(ans==tmp) puts("YES"); 170 else puts("NO"); 171 } 172 }View Code