1. 程式人生 > >Escape(狀態壓縮+最大流,好題)

Escape(狀態壓縮+最大流,好題)

 

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


Problem Description 2012 If this is the end of the world how to do? I do not know how. But now scientists have found that some stars, who can live, but some people do not fit to live some of the planet. Now scientists want your help, is to determine what all of people can live in these planets.  

 

Input More set of test data, the beginning of each data is n (1 <= n <= 100000), m (1 <= m <= 10) n indicate there n people on the earth, m representatives m planet, planet and people labels are from 0. Here are n lines, each line represents a suitable living conditions of people, each row has m digits, the ith digits is 1, said that a person is fit to live in the ith-planet, or is 0 for this person is not suitable for living in the ith planet.
The last line has m digits, the ith digit ai indicates the ith planet can contain ai people most..
0 <= ai <= 100000  

 

Output Determine whether all people can live up to these stars
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  

 

Source 2010 ACM-ICPC Multi-University Training Contest(17)——Host by ZSTU

 

 

在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