题意:有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; }