题意:
如果这是2012年世界末日怎么办?我不知道该怎么做。但是现在科学家们已经发现,有些星球上的人可以生存,但有些人却不适合居住。现在科学家们需要你的帮助,就是确定所有人都能在这些行星上生活。输入多组测试数据,每组数据的开头是n (1 <= n <= 100000), m (1 <= m <= 10) n表示地球上有n个人,m代表m星球,星球和人的标签都是从0开始的。这里有n行,每一行代表一个合适的居住条件的人,每一行有m个数字,第i个数字是1,表示一个人适合居住在第i个星球上,或者是0表示这个人不适合居住在第i个星球上。最后一行有m个数字,第i个数字ai表示第i个星球最能容纳ai人。0 <= ai <= 100000输出确定是否所有人都能达到这些标准如果可以输出YES,则输出NO。
代码:
1 //这道题一看见是一个最大流模板,但是这道题就是为了卡时间。。。 2 //因为题目上面n特别大,这个时候因为m只有10,此时最大也就只有2^10个选择,所以有好多人的选择是一样的 3 //那么我们要按照他们的选择来建图,这样的话边的数量就会大大减少 4 #include<stdio.h> 5 #include<string.h> 6 #include<iostream> 7 #include<algorithm> 8 #include<queue> 9 #include<math.h> 10 #include<stdlib.h> 11 #include<vector> 12 using namespace std; 13 const int maxn=200005; 14 const int INF=0x3f3f3f3f; 15 int head[maxn],cnt,st,en,dis[maxn],cur[maxn],v[maxn]; 16 struct edge 17 { 18 int v,next,c,flow; 19 } e[1000005]; 20 vector<int> state[maxn]; 21 void add_edge(int x,int y,int z) 22 { 23 e[cnt].v=y; 24 e[cnt].c=z; 25 e[cnt].flow=0; 26 e[cnt].next=head[x]; 27 head[x]=cnt++; 28 29 e[cnt].v=x; 30 e[cnt].c=z; 31 e[cnt].flow=0; 32 e[cnt].next=head[y]; 33 head[y]=cnt++; 34 } 35 bool bfs() 36 { 37 memset(dis,0,sizeof(dis)); 38 dis[st]=1; 39 queue<int>r; 40 r.push(st); 41 while(!r.empty()) 42 { 43 int x=r.front(); 44 r.pop(); 45 for(int i=head[x]; i!=-1; i=e[i].next) 46 { 47 int v=e[i].v; 48 if(!dis[v] && e[i].c>e[i].flow) 49 { 50 dis[v]=dis[x]+1; 51 r.push(v); 52 } 53 } 54 } 55 return dis[en]; 56 } 57 int dinic(int s,int limit) 58 { 59 if(s==en || !limit) return limit; 60 int ans=0; 61 for(int &i=cur[s]; i!=-1; i=e[i].next) 62 { 63 int v=e[i].v,feed; 64 if(dis[v]!=dis[s]+1) continue; 65 feed=dinic(v,min(limit,e[i].c-e[i].flow)); 66 if(feed) 67 { 68 e[i].flow+=feed; 69 e[i^1].flow-=feed; 70 limit-=feed; 71 ans+=feed; 72 if(limit==0) break; 73 } 74 } 75 if(!ans) dis[s]=-1; 76 return ans; 77 } 78 int main() 79 { 80 int n,m; 81 char s[25][25]; 82 int w[25][25]; 83 while(~scanf("%d%d",&n,&m)) 84 { 85 memset(head,-1,sizeof(head)); 86 cnt=0; 87 int x; 88 st=0; 89 en=1024+2*m+1; 90 memset(v,0,sizeof(v)); 91 // for(int i=1;i<=n;++i) //这种方法建图的时候它的终止点en要大于1024,这样的话跑的话太慢了 92 // { //所以这个时候en的大小要改变成n+m+1,这个时候就要用到n了,正确建图方式见下面 93 // int y=1,sum=0; 94 // for(int j=1;j<=m;++j) 95 // { 96 // scanf("%d",&x); 97 // if(x) 98 // { 99 // sum+=y; 100 // } 101 // y*=2; 102 // } 103 // v[sum]++; 104 // } 105 // if(v[0]) 106 // { 107 // printf("NO "); 108 // continue; 109 // } 110 // for(int i=1;i<=1024;++i) 111 // { 112 // if(v[i]) 113 // { 114 // add_edge(st,i,v[i]); 115 // add_edge(i,st,0); 116 // } 117 // for(int j=0;j<m;++j) 118 // { 119 // if((1<<j)&i) 120 // { 121 // add_edge(i,1024+1+j,INF); 122 // add_edge(1024+1+j,i,0); 123 // } 124 // } 125 // } 126 // for(int i=1;i<=m;++i) 127 // { 128 // scanf("%d",&x); 129 // add_edge(1024+i,en,x); 130 // add_edge(en,1024+i,0); 131 // } 132 st=0,en=n+m+1; 133 int s,i,j,num; //因此用状态压缩进行缩点 134 for(i=0; i<=1024; i++) 135 state[i].clear(); 136 for(i=1; i<=n; i++) 137 { 138 s=0; 139 for(j=0; j<m; j++) 140 { 141 scanf("%d",&num); 142 if(num==1) 143 s|=(1<<j); //C语言中的 |= 意思为:按位或后赋值 144 } 145 state[s].push_back(i); 146 } //缩点 147 int tmp,siz; 148 for(i=0; i<(1<<m); i++) //这点就比我原来的代码优化了 149 { 150 if(state[i].size()==0) 151 continue; 152 tmp=state[i][0]; 153 siz=state[i].size(); 154 add_edge(st,tmp,siz); 155 for(j=0; j<m; j++) //由原来容量为1改为缩点的个数 156 if(i&(1<<j)) 157 add_edge(tmp,n+j+1,siz); 158 } 159 for(i=1; i<=m; i++) 160 { 161 scanf("%d",&num); 162 add_edge(i+n,en,num); 163 } 164 165 int ans=0; 166 while(bfs()) 167 { 168 for(int i=0; i<=en; i++) 169 cur[i]=head[i]; 170 ans+=dinic(st,INF); 171 } 172 if(ans==n) 173 { 174 printf("YES "); 175 } 176 else printf("NO "); 177 } 178 return 0; 179 }