hdu 3605 Escape(最大流+状态压缩 or 二分图多重匹配)
2015-10-23 13:19
483 查看
Escape
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 7789 Accepted Submission(s): 1684
[align=left]Problem Description[/align]
2012 If this is the end of the world how to do? I do not know how. But now scientists have found that some stars, who can live, but some people do not fit to live some of the planet. Now scientists want your help, is to determine
what all of people can live in these planets.
[align=left]Input[/align]
More set of test data, the beginning of each data is n (1 <= n <= 100000), m (1 <= m <= 10) n indicate there n people on the earth, m representatives m planet, planet and people labels are from 0. Here are n lines, each line represents
a suitable living conditions of people, each row has m digits, the ith digits is 1, said that a person is fit to live in the ith-planet, or is 0 for this person is not suitable for living in the ith planet.
The last line has m digits, the ith digit ai indicates the ith planet can contain ai people most..
0 <= ai <= 100000
[align=left]Output[/align]
Determine whether all people can live up to these stars
If you can output YES, otherwise output NO.
[align=left]Sample Input[/align]
1 1 1 1 2 2 1 0 1 0 1 1
[align=left]Sample Output[/align]
YES NO 题意:有N个人要去M个星球避难,现在给你每个人适合居住的星球以及每个星球可以容纳的人数,问你这N个人能不能全部安全避难。 状态压缩,最大流。也可以用二分图多重匹配,代码更简单 参考大神分析: 由于N最大为100000,若直接建边的话,网络流的任何算法都承受不起这个时间复杂度。因为M个数最多为10, 利用状态来表示的话最坏只有2^10 = 1024个点,我们可以利用状态压缩的方法来优化时间复杂度。 建图:设置超级源点S,超级汇点T,并记录每个状态出现的次数。 1,S向所有状态建边,容量为该状态出现的次数; 2,所有状态向该状态里面存在的星球建边,容量为无穷大,表示S的流量可以无限到该星球; 3,对流入T的流量加限制,每个星球向T建边,容量为星球可以容纳的人数。 最后跑一次最大流,看是否满流就可以了 *///网络流 #include<stdio.h> #include<string.h> #include<algorithm> #include<queue> using namespace std; #define NN 100000+100 #define MM 20 int dis[NN],head[NN],cur[NN],rl[NN]; int S,T,cnt,n,m; struct node{ int v,next,w; }mp[NN*4]; void add(int u,int v,int w){ mp[cnt].v=v; mp[cnt].w=w; mp[cnt].next=head[u]; head[u]=cnt++; mp[cnt].v=u; mp[cnt].w=0; mp[cnt].next=head[v]; head[v]=cnt++; } int bfs(){ memset(dis,-1,sizeof(dis)); queue<int> Q; dis[S]=0; Q.push(S); while(!Q.empty()){ int u=Q.front(); Q.pop(); for(int i=head[u];i!=-1;i=mp[i].next){ int v=mp[i].v; if(dis[v]==-1 && mp[i].w){ dis[v]=dis[u]+1; if(v==T) return 1; Q.push(v); } } } return 0; } int dfs(int u,int flow){ if(u==T || flow==0) return flow; int i,a,ans=flow; for(int &i=cur[u];i!=-1;i=mp[i].next){ int v=mp[i].v; if( dis[v]==dis[u]+1 && mp[i].w && (a=dfs(v,min(ans,mp[i].w))) ){ mp[i].w-=a; mp[i^1].w+=a; ans-=a; if(ans==0) return flow; } } return flow-ans; } int dinic(){ int ans=0; while(bfs()){ memcpy(cur,head,sizeof(head)); ans+=dfs(S,0x3f3f3f3f); } return ans; } int main(){ int a,sum,k; while(~scanf("%d%d",&n,&m)){ //每个星球都有选和不选两种状态,所以最多有2^10=1024种状态,每种状态作为一个点最多1024个点 //再加星球有10个,所以 S=1024+10+1,T=S+1。 S=1035; T=S+1; sum=cnt=k=0; memset(head,-1,sizeof(head)); memset(rl,0,sizeof(rl)); for(int i=0;i<n;++i){ int temp=0; for(int j=0;j<m;++j){ scanf("%d",&a); if(a) temp += 1<<j;//记录状态 } rl[temp]++;//存该种状态出现的次数 } for(int i=0;i<(1<<m);++i){//每种状态遍历 if(rl[i]){ add(S,i,rl[i]); for(int j=0;j<m;++j){ if(i & (1<<j)) ////这个式子表示i那个位置的值是不是1,按位与运算 add(i,1025+j,0x3f3f3f3f);//星球的编号为1025+j } } } for(int i=0;i<m;++i){ scanf("%d",&a); add(1025+i,T,a); } k=dinic(); if(k==n) printf("YES\n",k); else printf("NO\n"); } return 0; } //二分图多重匹配 #include<stdio.h> #include<string.h> #define M 100000+100 #define N 20 int mp[M] ;//i适合在j上生存 int link [M];//link[i][j]表示i星球住了j个人 int vis ,cap ,num ;//表示星球的容量,num表示星球上的人数 int n,m; int dfs(int x){ for(int i=0;i<m;i++){ if(!vis[i] && mp[x][i]){ vis[i]=1; if(num[i]<cap[i]){//如果小于星球最大容量,就把这个人加进去 link[i][num[i]++]=x; return 1; } for(int j=0;j<num[i];j++){ if(dfs(link[i][j])){//查找增广路 link[i][j]=x; return 1; } } } } return 0; } int main(){ while(scanf("%d %d",&n,&m) == 2){ int ok=0; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ scanf("%d",&mp[i][j]); } } for(int i=0;i<m;i++) scanf("%d",&cap[i]); memset(num,0,sizeof(num)); for(int i=0;i<n;i++){ memset(vis,0,sizeof(vis)); if(!dfs(i)){ ok=1; break; } } if(ok) printf("NO\n"); else printf("YES\n"); } return 0; }
相关文章推荐
- 高级程序员不写代码?
- LeetCode "Best Meeting Point" !
- 算法竞赛入门-枚举-7.2.1-生成1~n排列
- C#基础知识
- vs2010 调试 数据便签中 查看字符串的全部字符
- Xcode 上传APP Error ITMS 90049 解决方案
- 关于动态规划
- CentOS7和win7双系统启动项
- ARC forbids explicit message send of release-关闭xCode项目的ARC设
- [HTML5学习]HTML5课程大纲介绍_cssl知识点整理
- Jmeter之Http Cookie Manager
- 【转】【Apache ZooKeeper】官方文档
- JSON的用法
- iOS开发:创建真机调试证书
- My coding way (4)
- Maven生命周期详解
- [转]Eclipse下tomcat输出路径配置
- xcode7 如何真机测试
- windows 安装 mysql
- Vbs脚本经典教材