/*
超时,不过不想找错误了!做这道题开始接触dinic算法
如果想要学dinic算法,参见:
http://wenku.baidu.com/view/98deaf06b52acfc789ebc91a.html###
http://www.cnblogs.com/ltang/archive/2010/11/17/1879573.html
题意:
X代表人,@代表教室门,问所有的人都跑出教室需要多久,每次只能走一步而且所走位置不能有人。
题解:最大流 + dinic算法
具体构图如下:
A: 增加源点src,和汇点dest,然后根据每个时间点建出分层图,每个时间对应一层,对于每层图的构造如下
B:给每个格子标上号Xi, 由于每个格子一次只能占一人,所以把每个格子分为两个点xa,xb,连上容量为1的有向边,对于格子为‘X’的,(如果为第0层的话)在源点src与xa之间连一条容量为1的有向边,对于格子为'@'的点,在xb与汇点dest连上容量为1的有向边,对于每个格子,(除‘#’外),在xb与其上下左右及其本身 的对应下一层图的xa连上容量为1 的一条有向边
C:具体操作并不是一下子建出分层图,由于时间是未知的,所以枚举时间,做最大流,当最大流小于人数时,时间加一并在原图上增加一层,继续求最大流,直到最大流大于等于人数,这时的时间就是答案
*/
#include <iostream>
#define re(i, n) for(int i = 0; i < n; ++ i)
using namespace std;
const int Max = 20;
const int nMax = 320000;
const int mMax = 3200000;
const int INF = 0x7fffffff;
char map[Max][Max];
int mark[Max][Max];
int d[Max][Max];
int qx[nMax], qy[nMax], k;
struct Edge
{
int v, w, next;
Edge(){}
Edge(int v, int w, int next): v(v), w(w), next(next){}
}adj[mMax];
int head[nMax], ind;
int dis[nMax];
int queue[nMax];
int dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
int num, node, z;
int s, t;
int n, m;
int MaxFlow;
void buildDi(int _k)//这个函数主要对矩阵进行处理,能够到门口的所有节点都满足d[i][j] != 0,便于判断是否存在无论如何也出不去的同学
{
memset(d, -1, sizeof(d));
for(int i = 0; i < _k; ++ i)
d[qx[i]][qy[i]] = 0;
for(int i = 0; i < _k; ++ i)
{
for(int j = 0; j < 4; ++ j)
{
int x = qx[i] + dir[j][0];
int y = qy[i] + dir[j][1];
if(x >= 0 && x < n && y >= 0 && y < m && map[x][y] != '#' && d[x][y] == -1)
{
d[x][y] = d[qx[i]][qy[i]] + 1;
qx[_k] = x;
qy[_k] = y;
_k ++;//对qx[],qy[]不断补充节点
}
}
}
}
bool ok()//判断X与@是否可通
{
re(i, n) re(j, m)
{
if(map[i][j] == 'X' && d[i][j] < 0) return 0;
}
return 1;
}
void addEdge(int u, int v, int w)
{
adj[ind] = Edge(v, w, head[u]);
head[u] = ind ++;
adj[ind] = Edge(u, 0, head[v]);
head[v] = ind ++;
}
void makeGraph()//每当时间增加1,则增加一层,建图参见上面详细介绍
{
node += 2 * z;
re(i, n) re(j, m)
if(mark[i][j])
{
addEdge(node + mark[i][j], node + mark[i][j] + z, 1);
addEdge(node + mark[i][j] - z, node + mark[i][j], 1);
if(map[i][j] == '@') addEdge(node + mark[i][j] + z, t, 1);
for(int k = 0; k < 4; ++ k)
{
int x = i + dir[k][0];
int y = j + dir[k][1];
if(x >= 0 && x < n && y >= 0 && y < m && mark[x][y])
addEdge(node + mark[x][y] - z, node + mark[i][j], 1);
}
}
}
int dinicBfs()//dinic算法中建层次图的部分,同时判断是否存在可行弧
{
memset(dis, -1, sizeof(dis));
int rear, front;
front = rear = 0;
queue[rear ++] = s;
dis[s] = 0;
while(front < rear)
{
int u = queue[front ++];
for(int id = head[u]; id != -1; id = adj[id].next)
{
int v = adj[id].v;
if(adj[id].w && dis[v] == -1)
//这里条件判断有疑问,因为这里建立层次图的目的是为了dinicDfs()可以查找到一条最短最广路,所以dis[v]之前应该没有被访问过
{
dis[v] = dis[u] + 1;
if(v == t) return 1;
queue[rear ++] = v;
}
}
}
return 0;
}
int dinicDfs(int cur, int cost = INF)//查找最短增广路径
{
if(cur == t) return cost;
int low;
int ans = 0;
for(int id = head[cur]; id != -1; id = adj[id].next)//这里其实并不只是寻找了一条增广路径,多条进行了汇合
{
int v = adj[id].v;
if(adj[id].w && (dis[v] == dis[cur] + 1) && (low = dinicDfs(v, min(adj[id].w ,cost))))
{
adj[id].w -= low;
adj[id ^ 1].w += low;
ans += low;//各条增广路径最大流量之和
cost -= low;//剩余可用流量
if(!cost) break;
}
}
return ans;
}
int dinicFlow()//dinic算法,输出最大流,因为题中特殊条件,所以MaxFlow需要定义成全局变量,并进行累加
{
while(dinicBfs())
MaxFlow += dinicDfs(s);
return MaxFlow;
}
int main()
{
//freopen("e://data.in", "r", stdin);
while(scanf("%d %d", &n, &m) != EOF)
{
num = 0;
k = 0;
z = 0;
re(i, n)
{
getchar();
re(j, m)
{
map[i][j] = getchar();
if(map[i][j] != '#') mark[i][j] = ++z;//每一层的节点数
else mark[i][j] = 0;
if(map[i][j] == '@') qx[k] = i, qy[k] = j, ++k;//存储教室门的坐标
if(map[i][j] == 'X') ++num;//总人数
}
}
buildDis(k);
if(!ok())
{
printf("-1\n");
continue;
}
s = 0;
t = 1;
node = 1;
ind = 0;
memset(head, -1, sizeof(head));
re(i, n) re(j, m)
{
if(mark[i][j])
{
if(map[i][j] == 'X') addEdge(s, mark[i][j] + node, 1);
addEdge(mark[i][j] + node, mark[i][j] + node + z, 1);
}
}
int ans = 0;
MaxFlow = 0;
while(dinicFlow() < num)
{
makeGraph();
ans++;
}
printf("%d\n", ans);
}
return 0;
}
分享到:
相关推荐
hdu 3341(ac自动机+状态压缩) 题意:容易理解... 思路:首先一开始容易想到要用到dp,开设一个dp[41][41][41][41][501]的数组来解决,但是明显内存已经超出范围了,于是就想如何减少内存呢?只要知道A、T、C、G其中...
ACM题库,一些题目和答案,以及解题报告,传上来共享
杭电OnlineJudge 200-2099的解题报告
acm hdu as easy as a+b
hdu ACM代码 每种算法都有分类 大三了,没有时间弄ACM,这些要删了
hdu 1695 GCD(欧拉函数+容斥原理).docx
很实用的算法讲解,hdu的lcy老师讲解,还不错!!
hdu动态规划算法集锦
本人准备2020年保研机试时刷的题目(虽然最后机试取消了,...来自某中流985,在HDU和vjudge平台上大概刷了400道。本文件地图(excel表格)包含了绝大部分我刷过的题目,笔记中具有思路、代码、总结和心得。 大佬勿入!
HDU的ACM,非常的好 涉及了很多算法,例如二分匹配、博弈、组合、最小生成树、搜索、动态规划、贪心算法
acm 技术大牛 课件 HDU 自学必备课件 全套齐全 (lecture_01)初识ACM (lecture_02)简单数学题 (lecture_03)递推求解 (lecture_04)动态规划(1)_ (lecture_05)计算几何基础_ (lecture_06)母函数 (lecture_...
Problem Description 话说,经过了漫长的一个多月,小明已经成长了许多,所以他改了一个名字叫“大明”。 这时他已经不是那个只会做100以内加法的那个“小明”了,现在他甚至会任意长度的正小数的加法。...
从简单入门到偏中等的几个题,线段树很灵活,主要懂了lazy操作,其他的自己yy吧。
杭州电子科技大学oj平台上的第1010题,是关于搜索的题目,很不错的题
算法-数塔(HDU-2084).rar
杭电ACM 培训课件,包括各种常用的算法,并结合例题详细的讲解,对提高算法思想用很大帮助
八数码的A*算法~不是很高效,但是很适合刚刚学这个算法的朋友们
300+ AC 代码 。 大数 , 线段树 , 字符串 , dp.....
08暑假集训搜索组解题报告 An Introduction to Recursion, Part 1.mht An Introduction to Recursion, Part 2.mht ...搜索入门 - from hdu.ppt 搜索算法的通用优化方法.pdf 谈搜索算法的剪枝优化.pdf
这是一个相当齐全的算法课件 里面包含了很多的内容和实例 使我们上课时老师的课件 希望对大家有帮助