HDU 3605 Escape 建图状态压缩

题意:有n个人,可以去m个星球定居,每个星球可以容纳的人数有限,每个人

可以有很多种选择,问你是否每个人都可以远离地球,定居到其它的星球去。

********保护环境啊!!!********

解题:虚拟一个source和sink,source到每一个人连一条容量为inf的边,每个人向他可以居住的星球连一条容量为1的边,每个星球向sink连一条容量为这个星球可以容纳的人的个数。

          但是有100000个人假设每个人只选择一个星球,那么就有(300000+星球数)条边

DINIC的时间O(边^2*点);TLE。

          可能存在k个人对于m个星球的选择是一样的,我们可以source到每一种选择连一条容量为(选择该选择的人的个数),然后每种选择向该选择里面的每一个可居住的星球连一条容量为inf的边,最后,每个星球向sink连一条容量为这个星球可以容纳的人的个数。

         状态压缩:

         1> 存储:mask|=1<<j:完成一个人的状态。

         ~1<<j:2^j     Binary:1000……00有j个0,‘|’:有1就是1       100110010|10000000=110110010

         2> 提取:现有状态110110010,问你第4个星球是否有人选择(从后往前),选择第4个星球的状态是1000。

         ~‘&’都是1才得1:if 110110010&1000=1表明现有状态里面选择了第四个星球,if =0表明现有状态里面没有选择。显然上面是数据是没有的。


#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#define inf 0x7fffffff 
using namespace std;
const int M=100000*2+20;
const int N=1000000+5;
int n,m;
int st,ed;
int nn;
struct nodee
{
	int v,next,flow;
}e[N*4];
int head[M],cnt;
int Scan()  
{  
    int res=0,ch,flag=0;  
    if((ch=getchar())=='-')              
        flag=1;  
    else if(ch>='0'&&ch<='9')         
        res=ch-'0';  
    while((ch=getchar())>='0'&&ch<='9')  
        res=res*10+ch-'0';  
    return flag?-res:res;  
}  
class Dinic
{
	public:
		int spath()
		{
			queue<int>q;
			while(!q.empty()) q.pop();
			memset(dis,-1,sizeof(dis));
			dis[st]=0;
			q.push(st);
			while(!q.empty())
			{
				int u=q.front();
				q.pop();
				for(int i=head[u];i+1;i=e[i].next)
				{
					int v=e[i].v;
					if(dis[v]==-1&&e[i].flow>0)
					{
						dis[v]=dis[u]+1;
						q.push(v); 
					}
				}
			}
			return dis[ed]!=-1;
		}
		int Min(int a,int b)
		{
			if(a<b) return a;
			return b;
		}
		int dfs(int u,int flow)
		{
			int cost=0;
			if(u==ed) return flow;
			for(int i=head[u];i+1;i=e[i].next)
			{
				int v=e[i].v;
				if(dis[v]==dis[u]+1&&e[i].flow>0)
				{
					int min=dfs(v,Min(e[i].flow,flow-cost));
					if(min>0)
					{
						e[i].flow-=min;
						e[i^1].flow+=min;
						cost+=min;
						if(cost==flow) break;
					}
					else dis[v]=-1;
				}
			}
			return cost;
		}
		int result()
		{
			int res=0;
			while(spath())
			{
				res+=dfs(st,inf);
			}
			return res;
		}
	private:
		int dis[M];
}dinic;
void Init()
{
	memset(head,-1,sizeof(head));
	cnt=0;
}
void add(int a,int b,int c)
{
	e[cnt].v=b;
	e[cnt].flow=c;
	e[cnt].next=head[a];
	head[a]=cnt++;
	
	e[cnt].v=a;
	e[cnt].flow=0;
	e[cnt].next=head[b];
	head[b]=cnt++;
}
void Input()
{
	int mark[1024+20];
	memset(mark,0,sizeof(mark));
	for(int i=1;i<=n;i++)
	{
		int mask=0;
		for(int j=1;j<=m;j++)
		{
			int key;
			key=Scan();
			if(key) mask|=1<<(j-1);
		}
		mark[mask]++;
	}
	nn=n;
	n=1<<m;
	st=0;ed=n+m+50;
	for(int i=1;i<=n;i++)
	{
		if(mark[i])
		{
			add(st,i,mark[i]);
			for(int j=0;j<m;j++)
			{
				if(i&(1<<j))
				add(i,n+j+1,inf);
			}
		}
	}
	for(int i=1;i<=m;i++)
	{
		int key;
		key=Scan();
		if(key)
	    add(i+n,ed,key);
	}
}
void treatment()
{
	int k=dinic.result();
	if(k==nn) printf("YES\n");
	else printf("NO\n");
}
int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		Init();
		Input();
		treatment();
	}
	return 0;
} 





你可能感兴趣的:(网络流)