Escape(状态压缩+最大流,好题)
Posted fighting-sh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
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.
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
在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 }
以上是关于Escape(状态压缩+最大流,好题)的主要内容,如果未能解决你的问题,请参考以下文章
[dfs] aw166. 数独(dfs剪枝与优化+状态压缩+代码技巧+好题)