M - Escape - HDU 3605 - (缩点+最大流SAP)
题目大意:2012世界末日来了,科学家发现了一些星球可以转移人口,不过有的人可以在一些星球上生存有的人不行,而且每个星球都有一定的承载量,现在想知道是否所有的人都可以安全转移呢?
输入:首先输入一个N和M,表示人数和星球数,接着输入N行,每行有M个01组成的数,0表示第Ni个人无法再Mj号星球上生存,1表示可以生存,最后一行是每个星球的最大承载量。
分析:刚看的时候是一道比较裸的最大流题目,只要求出来最大流是否等于总人口数就行了,不过人的数量貌似是有点多的,刚开始没有管那么多直接上了最大流,不过也果然TLE,后来借鉴了一下别人的想法,就是缩点,我们发现M的值是特别小的,最大只有10,这就意味着有很多人的状态是相同的(2^10),所以可以把这些状态相同的人压缩到一起,这样最多也就1024个人了,大大缩减了复杂度,不过很不幸依然TLE!!!,好吧,认了,只能再去找一下sap的模板带入一下,刚开始随意找了一个模板套上,不过WA了,也不知道出了什么问题,,因为不了解SAP这东西,没办法,只能学一下SAP了,在网上找了一个很不错的演示 。其实和dinic还是挺相似的,只不过这个只做了一次的DFS是从汇点到源点进行的分层,然后寻找可行弧(也就是下面有没有可以与之相连的边),如果没有可行弧,就修改他的层号,然后就这样一直找下去,直到源点的层号大于总点数或者出现断层就可以停止了。ps.生命不息,学习不止啊。
sap演示 下载
======================================================================================
#include<stdio.h>
#include<string.h>
#include<queue>
#include<math.h>
#include<algorithm>
using namespace std; const int MAXN = ;
const int oo = 1e9+; struct Edge{int u, v, flow, next;}edge[MAXN*];
int Head[MAXN], cnt;
int used[MAXN], cur[MAXN], Stack[MAXN];
int Layer[MAXN], gap[MAXN], cntv;///节点的总个数 void InIt()
{
cnt = ;
memset(Head, -, sizeof(Head));
memset(used, , sizeof(used));
}
void AddEdge(int u, int v, int flow)
{
edge[cnt].u = u;
edge[cnt].v = v;
edge[cnt].flow = flow;
edge[cnt].next = Head[u];
Head[u] = cnt++; edge[cnt].u = v;
edge[cnt].v = u;
edge[cnt].flow = ;
edge[cnt].next = Head[v];
Head[v] = cnt++;
} void BFS(int End)
{
memset(Layer, -, sizeof(Layer));
memset(gap, , sizeof(gap));
queue<int> Q;
Q.push(End);
Layer[End] = , gap[] = ; while(Q.size())
{
int u = Q.front();
Q.pop(); for(int j=Head[u]; j!=-; j=edge[j].next)
{
int v = edge[j].v; if(Layer[v] == -)
{
Layer[v] = Layer[u] + ;
gap[Layer[v]]++;
Q.push(v);
}
}
}
} int SAP(int start, int End)
{
int j, top=, u = start, MaxFlow=; BFS(End);
cntv = End;
memcpy(cur, Head, sizeof(Head)); while(Layer[start] < cntv)
{///源点的层次小于总结点数,汇点是0层 if(u == End)
{
int MinFlow = oo, location;///记录下最小流量边的位置,出栈时候用 for(j=; j<top; j++)
{
int i = Stack[j];
if(MinFlow > edge[i].flow)
{
MinFlow = edge[i].flow;
location = j;
}
}
for(j=; j<top; j++)
{///所有的边减去路径上的最小流量
int i = Stack[j]; edge[i].flow -= MinFlow;
edge[i^].flow += MinFlow;
} MaxFlow += MinFlow;
top = location;///退栈
u = edge[Stack[top]].u;
}
else if(gap[Layer[u]-] == )
break;///u所在的层下面的层没有了,出现了断层,也就没有了可行弧 for(j=cur[u]; j!=-; j=edge[j].next)
{///如果u有可行弧就停止
if(Layer[u]==Layer[edge[j].v]+ && edge[j].flow)
break;
} if(j != -)
{///找到了可行弧
cur[u] = j;///u点的可行弧是j
Stack[top++] = j;///记录下这条边
u = edge[j].v;
}
else
{///没有找到可行弧,修改标号
int MinIndex = cntv; for(j=Head[u]; j!=-; j=edge[j].next)
{///查找与u相连的最小的层是多少
if(edge[j].flow && MinIndex > Layer[edge[j].v])
{///记录下这条可行弧,下次可以直接访问这条边
MinIndex = Layer[edge[j].v];
cur[u] = j;
}
} gap[Layer[u]] -= ;///u改变层,所以u原来所在层的点数减去1
Layer[u] = MinIndex + ;
gap[Layer[u]] += ; if(u != start)
{///返回上一层
u = edge[Stack[--top]].u;
}
}
} return MaxFlow;
} int main()
{
int N, M; while(scanf("%d%d", &N, &M) != EOF)
{
int i, j, u, Ni=pow(, M), start=Ni+M+, End=start+;
char ch; InIt(); for(i=; i<=N; i++)
{
u = ;
for(j=; j<=M; j++)
{
while(ch = getchar(), ch ==' ' || ch == '\n');
u = u* + ch-'';
}
used[u]++;///这种状态的人+1
} for(i=; i<Ni; i++)
{
if(used[i])
{
AddEdge(start, i, used[i]);
}
} for(i=; i<=M; i++)
{
scanf("%d", &u);
AddEdge(i+Ni, End, u);
} for(i=; i<Ni; i++) if(used[i])
{///如果这种状态有人
u = i;
for(j=M; j>; j--)
{
if(u&)
{///最后一位是1
AddEdge(i, Ni+j, used[i]);
}
u = u >> ;
}
} int MaxFlow = SAP(start, End); if(MaxFlow == N)
printf("YES\n");
else
printf("NO\n");
} return ;
}
M - Escape - HDU 3605 - (缩点+最大流SAP)的更多相关文章
- Escape HDU - 3605(归类建边)
Escape Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Subm ...
- hdu 3605 /状态合并最大流
题意:N个人去m个星球,给出n个人可以去哪些星球的01矩阵.求是否能满足所有人都去.(n到10万,m<=10) 一看,起先一瞬间就建图,准备秒了,人向星球连边,直接最大流判断是否为n,提交超时. ...
- 网络流 E - Escape HDU - 3605
2012 If this is the end of the world how to do? I do not know how. But now scientists have found tha ...
- Hdu 3605 Escape (最大流 + 缩点)
题目链接: Hdu 3605 Escape 题目描述: 有n个人要迁移到m个星球,每个星球有最大容量,每个人有喜欢的星球,问是否所有的人都能迁移成功? 解题思路: 正常情况下建图,不会爆内存,但是T ...
- HDU 3605 Escape(状压+最大流)
Escape Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Sub ...
- HDU 3605 Escape (网络流,最大流,位运算压缩)
HDU 3605 Escape (网络流,最大流,位运算压缩) Description 2012 If this is the end of the world how to do? I do not ...
- HDU - 3605 Escape (缩点+最大流/二分图多重匹配)
题意:有N(1<=N<=1e5)个人要移民到M(1<=M<=10)个星球上,每个人有自己想去的星球,每个星球有最大承载人数.问这N个人能否移民成功. 分析:可以用最大流的思路求 ...
- HDU 3605 Escape 最大流+状压
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=3605 Escape Time Limit: 2000/1000 MS (Java/Others) ...
- HDU 3605:Escape(最大流+状态压缩)
http://acm.hdu.edu.cn/showproblem.php?pid=3605 题意:有n个人要去到m个星球上,这n个人每个人对m个星球有一个选择,即愿不愿意去,"Y" ...
随机推荐
- 一道在知乎很火的 Java 题——如何输出 ab【转】
这是一个源自知乎的话题,原贴链接:一道百度的面试题,有大神会嘛? 虽然我不是大神,但我也点进去看了一下,思考了一会之后有了一些思路,然后去看其它人的答案的时候果然全都已经被各路大神们先想到并贴出来了, ...
- Android中SQLite使用
现在的主流移动设备像Android.iPhone等都使用SQLite作为复杂数据的存储引擎,在我们为移动设备开发应用程序时,也许就要使用到SQLite来存储我们大量的数据,所以我们就需要掌握移动设备上 ...
- javaScript特效
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- Phonegap 极光推送api 服务器端推送代码
.net 版本 极光推送 后台接口 HttpWebResponseUtility类 using System; using System.Collections.Generic; using Syst ...
- 64位Window操作系统下,Orcal数据访问服务器端和客户端版本对应与通讯问题
最近做一个小系统,需要在客户现场搭建数据库环境.之前我们一直访问的是公司的一个测试库,现在需要在现场开发,现场的Orcal服务器是12C ,我们本不打算重装服务器端orcal,故将我们自己电脑的orc ...
- [转]Delphi中进行延时的4种方法
1.挂起,不占CPU sleep 2.不挂起,占cpu procedure Delay(msecs:integer); var FirstTickCount:longint; begin FirstT ...
- Object Storage(Swift)安装过程——Havana
自从看了Havana安装文档有关Swift的安装一节,发现H版的安装过程与以前还是有些差别的.不过大致过程还是那些.下面简单介绍下我们安装的过程吧,具体请参考官方文档http://docs.opens ...
- 开始编写正式的iOS 程序(iOS编程指导)
App设计基础 在确定了你的App主要功能后,需要把它转化为代码.如果你是第一次开发属于自己的iOS App,需要花些时间熟悉基本概念.iOS内置了很多设计样式,多了解下能对你以后有帮助. 初稿 设计 ...
- js中callee与caller的区别
callee是对象的一个属性,该属性是一个指针,指向参数arguments对象的函数首先我们来写个阶成函数:function chen(x){if (x<=1) {return 1;} else ...
- Spring MVC PageNotFound.noHandlerFound No mapping found for HTTP request with URI
首先骂人,干他娘的,弄了两个小时原来的包倒错了!!唉TMD. 注意用IDEA倒包的时候一定要注意ModelAndView是 原因是import出错了!!应该是import org.springfram ...