题目链接:
http://acm.split.hdu.edu.cn/showproblem.php?pid=3605
题目大意:
有N个人,M个星球,每个人都有自己想要去的星球(多个中选取一个),每个星球都有自己的容纳量,问能否让所有人都登陆自己想要的星球。
题目思路:
由于N很大,直接建图会T,因为最多有十个星球,所以我们就可以采用状态压缩,所有人选择的状态最多有2^10种。最多需要1024个点。
那么,人分类成状态然后进行建图。
建图过程:
1.建源点和汇点。
2.源点与每一种状态相连,容量为该状态的人数。
3.每一种状态与该状态下能够生存的星球相连接,容量为该状态的人数。
4.每一个星球与汇点相连接,容量为该星球的人数。
最后跑一遍最大流,与总人数判断即可。
学到的东西:
建图的思想,当只有1或0两种选择时,要考虑是否采用二进制状态压缩的方法。
代码:
#include <bits/stdc++.h>
using namespace std;
#define maxn 2000
#define INF 0xfffffff
int deep[maxn],N,M,cnt,head[maxn]; //N是顶点数
int status[2049];
int s,t; //
struct Edge
{
int v,cap;
int next;
}edge[maxn*maxn];//邻接表
int bfs()
{
memset(deep,-1,sizeof(deep));
queue<int>q;
q.push(s);
deep[s]=0;
while(!q.empty())
{
int now=q.front();
q.pop();
for(int nex=head[now];nex!=-1;nex=edge[nex].next)
{
if(deep[edge[nex].v]==-1&&edge[nex].cap>0)
{
deep[edge[nex].v]=deep[now]+1;
q.push(edge[nex].v);
}
}
}
if(deep[t]==-1) return 0;
return 1;
}
int Min(int a,int b)
{
return a<b?a:b;
}
int dfs(int pos,int flow)
{
if(pos==t) return flow;
int t=0,sum=0;
for(int nex=head[pos];nex!=-1;nex=edge[nex].next)
{
if(deep[edge[nex].v]==deep[pos]+1&&edge[nex].cap>0)
{
t=dfs(edge[nex].v,Min(flow-sum,edge[nex].cap));
if(t>0)
{
edge[nex].cap-=t;
edge[nex^1].cap+=t;
sum+=t;
if(sum==flow) break;
}
else deep[edge[nex].v]=-1;
}
}
return sum;//当前点可增广的最大流量
}
int dinic()
{
int sum=0;
while(bfs())
sum+=dfs(s,INF);
return sum;
}
void add(int u,int v,int w)
{
//u->v
edge[cnt].v=v;
edge[cnt].cap=w;
edge[cnt].next=head[u];
head[u]=cnt++;
//v->u
edge[cnt].v=u;
edge[cnt].cap=0;
edge[cnt].next=head[v];
head[v]=cnt++;
}
void init()
{
memset(head,-1,sizeof(head));
memset(status,0,sizeof(status));
s=0;
t=1999;
}
int main()
{
while(~scanf("%d%d",&N,&M)){//N是人的个数 M是星球的个数
init();
for(int i=1;i<=N;i++){
int sum=0;
for(int j=1;j<=M;j++){
sum<<=1;
int x;scanf("%d",&x);
sum+=x;
}
status[sum]++;
}
for(int i=1;i<=M;i++){
int x;scanf("%d",&x);
add(1024+i,t,x);
}
for(int i=0;i<=1024;i++){
if(status[i]!=0){
add(s,i,status[i]);
int tmp=i;
for(int j=1;j<=M;j++){
if((tmp>>(j-1))&1)
add(i,1024+j,status[i]);
}
}
}
if(N<=dinic()) printf("YES\n");
else printf("NO\n");
}
}