题意:
如果这是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\n");
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\n");
175 }
176 else printf("NO\n");
177 }
178 return 0;
179 }