Escape(状态压缩+最大流,好题)

Escape

http://acm.hdu.edu.cn/showproblem.php?pid=3605

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 13201    Accepted Submission(s): 3329

Problem Description

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.

Input

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

Output

Determine whether all people can live up to these stars
If you can output YES, otherwise output NO.

Sample Input

1 1

1

1

2 2

1 0

1 0

1 1

Sample Output

YES

NO

Source

2010 ACM-ICPC Multi-University Training Contest(17)——Host by ZSTU

在TLE n次之后,才反应过来,n太大了。。。

百度之后才知道,需要用类似状态压缩的方法

因为m<=10,所以状态数量只有1000左右,把每个会遇到的状态数的数量记录下来,从源点到左边的点拉容量为a[i]的边,左边的点到右边的点拉容量为INF的边,右边的点到汇点拉容量为ci的边

  1 #include<iostream>
  2 #include<cstring>
  3 #include<string>
  4 #include<cmath>
  5 #include<cstdio>
  6 #include<algorithm>
  7 #include<queue>
  8 #include<vector>
  9 #include<set>
 10 #define maxn 200005
 11 #define MAXN 200005
 12 #define mem(a,b) memset(a,b,sizeof(a))
 13 const int N=200005;
 14 const int M=200005;
 15 const int INF=0x3f3f3f3f;
 16 using namespace std;
 17 int n;
 18 struct Edge{
 19     int v,next;
 20     int cap,flow;
 21 }edge[MAXN*20];//注意这里要开的够大。。不然WA在这里真的想骂人。。问题是还不报RE。。
 22 int cur[MAXN],pre[MAXN],gap[MAXN],path[MAXN],dep[MAXN];
 23 int cnt=0;//实际存储总边数
 24 void isap_init()
 25 {
 26     cnt=0;
 27     memset(pre,-1,sizeof(pre));
 28 }
 29 void isap_add(int u,int v,int w)//加边
 30 {
 31     edge[cnt].v=v;
 32     edge[cnt].cap=w;
 33     edge[cnt].flow=0;
 34     edge[cnt].next=pre[u];
 35     pre[u]=cnt++;
 36 }
 37 void add(int u,int v,int w){
 38     isap_add(u,v,w);
 39     isap_add(v,u,0);
 40 }
 41 bool bfs(int s,int t)//其实这个bfs可以融合到下面的迭代里,但是好像是时间要长
 42 {
 43     memset(dep,-1,sizeof(dep));
 44     memset(gap,0,sizeof(gap));
 45     gap[0]=1;
 46     dep[t]=0;
 47     queue<int>q;
 48     while(!q.empty())
 49     q.pop();
 50     q.push(t);//从汇点开始反向建层次图
 51     while(!q.empty())
 52     {
 53         int u=q.front();
 54         q.pop();
 55         for(int i=pre[u];i!=-1;i=edge[i].next)
 56         {
 57             int v=edge[i].v;
 58             if(dep[v]==-1&&edge[i^1].cap>edge[i^1].flow)//注意是从汇点反向bfs,但应该判断正向弧的余量
 59             {
 60                 dep[v]=dep[u]+1;
 61                 gap[dep[v]]++;
 62                 q.push(v);
 63                 //if(v==sp)//感觉这两句优化加了一般没错,但是有的题可能会错,所以还是注释出来,到时候视情况而定
 64                 //break;
 65             }
 66         }
 67     }
 68     return dep[s]!=-1;
 69 }
 70 int isap(int s,int t)
 71 {
 72     if(!bfs(s,t))
 73     return 0;
 74     memcpy(cur,pre,sizeof(pre));
 75     //for(int i=1;i<=n;i++)
 76     //cout<<"cur "<<cur[i]<<endl;
 77     int u=s;
 78     path[u]=-1;
 79     int ans=0;
 80     while(dep[s]<n)//迭代寻找增广路,n为节点数
 81     {
 82         if(u==t)
 83         {
 84             int f=INF;
 85             for(int i=path[u];i!=-1;i=path[edge[i^1].v])//修改找到的增广路
 86                 f=min(f,edge[i].cap-edge[i].flow);
 87             for(int i=path[u];i!=-1;i=path[edge[i^1].v])
 88             {
 89                 edge[i].flow+=f;
 90                 edge[i^1].flow-=f;
 91             }
 92             ans+=f;
 93             u=s;
 94             continue;
 95         }
 96         bool flag=false;
 97         int v;
 98         for(int i=cur[u];i!=-1;i=edge[i].next)
 99         {
100             v=edge[i].v;
101             if(dep[v]+1==dep[u]&&edge[i].cap-edge[i].flow)
102             {
103                 cur[u]=path[v]=i;//当前弧优化
104                 flag=true;
105                 break;
106             }
107         }
108         if(flag)
109         {
110             u=v;
111             continue;
112         }
113         int x=n;
114         if(!(--gap[dep[u]]))return ans;//gap优化
115         for(int i=pre[u];i!=-1;i=edge[i].next)
116         {
117             if(edge[i].cap-edge[i].flow&&dep[edge[i].v]<x)
118             {
119                 x=dep[edge[i].v];
120                 cur[u]=i;//常数优化
121             }
122         }
123         dep[u]=x+1;
124         gap[dep[u]]++;
125         if(u!=s)//当前点没有增广路则后退一个点
126         u=edge[path[u]^1].v;
127      }
128      return ans;
129 }
130
131 int a[maxn];
132
133 int main(){
134     int m,s,t;
135     while(~scanf("%d %d",&n,&m)){
136         int b,c;
137         memset(a,0,sizeof(a));
138         int Max=0;
139         isap_init();
140         for(int i=1;i<=n;i++){
141             int tmp=0;
142             for(int j=1;j<=m;j++){
143                 scanf("%d",&c);
144                 tmp=(tmp<<1)|c;
145             }
146             if(Max<tmp) Max=tmp;
147             a[tmp]++;
148         }
149         s=0,t=Max+m+1;
150         for(int i=1;i<=m;i++){
151             scanf("%d",&c);
152             add(Max+i,t,c);
153         }
154         for(int i=1;i<=Max;i++){
155             if(a[i]>0){
156                 add(s,i,a[i]);
157                 int k=m,p=i;
158                 while(k&&p){
159                     int tmp=p%2;
160                     p/=2;
161                     if(tmp>0) add(i,Max+k,INF);
162                     k--;
163                 }
164             }
165         }
166         int tmp=n;
167         n=Max+m+2;
168         int ans=isap(s,t);
169         if(ans==tmp) puts("YES");
170         else puts("NO");
171     }
172 }

原文地址:https://www.cnblogs.com/Fighting-sh/p/9951520.html

时间: 2024-11-05 18:53:17

Escape(状态压缩+最大流,好题)的相关文章

HDU 3605 —— Escape 状态压缩+最大流

原题:http://acm.hdu.edu.cn/showproblem.php?pid=3605 #include<cstdio> #include<cstring> #include<string> #include<queue> #include<cmath> #include<vector> #include<algorithm> #define inf 1e9 using namespace std; const

状态压缩dp入门 第一题 POJ 3254 Corn Fields

Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 6460   Accepted: 3436 Description Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yumm

HDU 3605 Escape(状态压缩+最大流)

http://acm.hdu.edu.cn/showproblem.php?pid=3605 题意: 有n个人和m个星球,每个人可以去某些星球和不可以去某些星球,并且每个星球有最大居住人数,判断是否所有人都能去这m个星球之中. 思路: 这道题建图是关键,因为n的数量很大,如果直接将源点和人相连,是会超时的,因为m≤10,所以每个人的选择可以用二进制来存储,这样最多也就1<<m-1种状态,相同的就可以放在一起处理了. 1 #include<iostream> 2 #include&l

HDU3605(KB11-M 状态压缩+最大流)

Escape Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 10920    Accepted Submission(s): 2630 Problem Description 2012 If this is the end of the world how to do? I do not know how. But now scient

Victor and World(spfa+状态压缩dp)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5418 Victor and World Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/131072 K (Java/Others)Total Submission(s): 958    Accepted Submission(s): 431 Problem Description After trying hard fo

hdu3605(最大流+状态压缩)

传送门:Escape 题意:给出每个人适合住的星球信息和该星球能住多少人 ,第一行给出n m 代表有 n 个人 m 个星球,然后接下来n行每行m个数字 1代表适合第 i 个星球 0 代表不适合第 i 个星球,最后一行m个数表示第 i 个星球最多可以住多少个人,问是不是所有人都可以住到星球上. 分析:很裸的最大流,但刚开始直接去建图,100W级别的边MLE了,就算没MLE也会TLE的,因此需要状态压缩,m<=10,最多1024种状态,边数降成1W级别,最大流妥妥的A了. #pragma comme

初步了解--状态压缩dp---poj1185炮兵布阵结题报告

好吧,借助poj1185炮兵布阵这题,仔仔细细的了解了一下状态压缩动态规划 首先,借助题目,我们来看看状态压缩是个虾米东西..Ok follow me 一,所谓状态压缩 根据题意,我们得在长度为M 的地图上放置一些大炮(后面简称"放炮",应该不会被和谐吧),那么,首先不考虑山地,我们得把所有的放置方法都找出来,并且注意,这里只对于一行且长度为M(好吧,你可能要问考虑一行,左右互相隔2,互相不在攻击范围,那么上下呢?这里先不急,一步步来) 1,找出所有放炮的方法 假设长度为7,那么看下图

POJ-3254-Corn Fields-DP+状态压缩(入门题)

题目链接:http://poj.org/problem?id=3254 题目意思:给你一个n*m的牧场,叫你带牛去吃草,其中0代表没有草不可以放牧,1代表有草可以放牧.而且两头牛不可以相邻,叫你求所有可能的放牧方案. 思路:这是个状态压缩的基础题,刚学状态压缩的可以用这个题目来理解状态压缩:(如果是刚学DP我建议理解题意后先粗略的看一下代码后再边看代码边看我的思路,效果更佳) 1.题目告诉我们两头牛不能相邻,那么我们就可以枚举出每一行的所有情况,并且用数组st保存起来:怎么枚举每一种情况呢,题目

poj1185炮兵布阵结题报告--初步了解--状态压缩dp

好吧,借助poj1185炮兵布阵这题,仔仔细细的了解了一下状态压缩动态规划 首先,借助题目,我们来看看状态压缩是个虾米东西..Ok follow me 一,所谓状态压缩 根据题意,我们得在长度为M 的地图上放置一些大炮(后面简称"放炮",应该不会被和谐吧),那么,首先不考虑山地,我们得把所有的放置方法都找出来,并且注意,这里只对于一行且长度为M(好吧,你可能要问考虑一行,左右互相隔2,互相不在攻击范围,那么上下呢?这里先不急,一步步来) 1,找出所有放炮的方法 假设长度为7,那么看下图