HDU 3605
Sample Input
1 1
1
1
2 2
1 0
1 0
1 1
Sample Output
YES
NO
题意:n个人,m个星球,然后给你一个n*m的矩阵,如果第i行第j列为1,说明第i个人可以居住在第j个星球上,0则说明不能。最后一行m个数据,表示对应的星球可以容纳的最大人数。问你最后能不能找到一种方法可以让所有人都有地方住。
解题思路:很明显的最大流的题目,1<=n<=1e5,1<=m<=10。就常规的建图会卡RE和卡T,所以需要进行缩点,状态压缩(对这种感觉不是很敏感,可惜。。),因为最多只有10个星球,那么每个人可能有的选择只有2^10种,而n有1e5,说明会有很多重复的人,那这些重复的人实际上是没有区别的。所以我们选择缩点,对选择完全的一样的人进行合并,这样就等于最多只用建1024个点和源点连接了,大大减少了边的数量,流量就为个数就行了,后面的就常规了,可以连的星球就连,星球再与汇点连边流量为限制的最多人数就可以了。这种匹配的题用匈牙利匹配也可以做。
完整代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=1005;
const int inf=0x3f3f3f3f;
struct Edge{
int u,v,c;
int next;
}edge[maxn*20];
int n,m;
int edn;//边数
int head[maxn*20],dis[maxn*20];
int sp,tp;//原点,汇点
void addedge(int u,int v,int c)
{
edge[edn].u=u; edge[edn].v=v; edge[edn].c=c;
edge[edn].next=head[u]; head[u]=edn++;
edge[edn].u=v; edge[edn].v=u; edge[edn].c=0;
edge[edn].next=head[v]; head[v]=edn++;
}
int bfs()
{
queue <int> q;
memset(dis,-1,sizeof(dis));
dis[sp]=0;
q.push(sp);
while(!q.empty())
{
int cur=q.front();
q.pop();
for(int i=head[cur];i!=-1;i=edge[i].next)
{
int u=edge[i].v;
if(dis[u]==-1 && edge[i].c>0)
{
dis[u]=dis[cur]+1;
q.push(u);
}
}
}
return dis[tp] != -1;
}
int dfs(int a,int b)
{
int r=0;
if(a==tp) return b;
for(int i=head[a];i!=-1 && r<b;i=edge[i].next)
{
int u=edge[i].v;
if(edge[i].c>0 && dis[u]==dis[a]+1)
{
int x=min(edge[i].c,b-r);
x=dfs(u,x);
r+=x;
edge[i].c-=x;
edge[i^1].c+=x;
}
}
if(!r)dis[a]=-2;
return r;
}
int dinic(int sp,int tp)
{
int total=0,t;
while(bfs())
{
while(t=dfs(sp,inf))
total+=t;
}
return total;
}
int a[1050];
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
edn=0;
memset(head,-1,sizeof(head));
memset(a,0,sizeof(a));
sp=0,tp=1024+m+1;
for(int i=1;i<=n;i++)
{
int q=0;
for(int j=1;j<=m;j++)
{
int x;
scanf("%d",&x);
if(x==1)
q=q|(1<<(j-1));
}
a[q]++;
}
for(int i=1;i<=1024;i++)
{
if(a[i])
addedge(sp,i,a[i]);
for(int j=1;j<=m;j++)
{
if(i&(1<<(j-1)))
addedge(i,1024+j,a[i]);
}
}
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
// addedge(n+i,n+i+m,x);
addedge(i+1024,tp,x);
}
int ans=dinic(sp,tp);
if(ans==n)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}