您的位置:首页 > 运维架构

UVA Live 6474 Drop Zone 最小割=最大流

2017-07-16 21:47 302 查看
Time Limit: 3000ms

Problem description

Evacuation missions and supply gathering missions are conducted on a regular basis by special teams.One of the first objectives of these missions is to set up a perimeter with barricades. Barricades arecostly and take time to
set up, so it is important to reduce the number of barricades necessary to blockoff an area.You will be provided with several maps of high-interest drop zones. It is your job to write a programthat will output the minimum number of barricades required for
each drop zone.Zombies will begin their approach from outside the map, thus any open area on the border isaccessible to zombies. Barricades can be placed between any two adjacent open areas (including thedrop zone) to block zombie movement. All zones outside
of the map should be considered open areas.Here is an example of one of the maps you will be provided:

XXX..XXX

XXX..XXX

.....XXX

XXX..XXX

XDDDD.XX

XDDDD...

XXXXXXXX

Symbol Description



Impassible, zombies cannot move through these areas

.(period) 

Open area, zombies can move through these zones, but not diagonally. Barricadesmay be placed between these areas.



Drop zone, this zone must be protected at all costs. Barricades must effectively block zombie movement from the edges of the map to this zone. This area is treated like an open area for zombie movement and barricade placement.
There will be exactly one contiguous drop zone in every map. Drop zones may be on the edges of the map.

Input
The first number, N (1 <= N <= 20), will be the number of maps. For each map, there will be two parameters, R and C (1 <= R, C <= 150), denoting the number of rows and columns in the map, followed by the map itself as described above. Each row will be on its
own line and all rows will have the same number of characters equal to C.
Output
For each map, print a single line containing the minimum number of barricades required to block off the drop zone.
Sample Input
2
7 8
XXX..XXX
XXX..XXX
.....XXX
XXX..XXX
XDDDD.XX
XDDDD...
XXXXXXXX
5 5
XX.XX
.DDD.
XD.DX
X....
X....

Sample Output
3
6

一个n*m的地图,字符 ‘.’ 表示可以到达,X表示不可到达,D表示可以到达,是安全地带。

现在要在地图里建一些栅栏,把所有D围起来,使D区域不能从外部边界进入。

这题实际上是在建好的图上求最小割,而最小割和最大流相等,可以用dinic算法求出。

地图上可以互相到达的点之间建一条边,流量为1。

建立一个源点,连接边界上所有可以到达的点,流量取决于该格子有几条边在边界上。

建立一个汇点,连接所有地图上为D的格子,流量为4.(因为可以从最多四个方向进入)

如果D在边界上,直接连接源点和汇点即可,流量取决于D有几条边在边界上。

这样建好图之后,直接跑一遍最大流就可以了。

数据好弱啊,只跑了9ms...

#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
const int maxn=25005,maxk=112505,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
int num;
int head[maxn],dist[maxn],current[maxn],visit[maxn];
char mp[155][155];

struct Edge {
int from,to,flow,pre;
};
Edge edge[maxk];

void addedge(int from,int to,int flow) {
edge[num]=(Edge){from,to,flow,head[from]};
head[from]=num++;
edge[num]=(Edge){to,from,0,head[to]};
head[to]=num++;
}

bool bfs (int n) {
queue<int> q;
q.push(0);
memset(dist,-1,sizeof(dist));
dist[0]=0;
while (!q.empty()) {
int now=q.front();
q.pop();
for (int i=head[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
if (dist[to]==-1&&edge[i].flow>0) {
dist[to]=dist[now]+1;
q.push(to);
}
}
}
return dist
!=-1;
}

int dfs(int now,int flow,int n) {
int f;
if (now==n) return flow;
for (int i=current[now];i!=-1;i=edge[i].pre) {
int to=edge[i].to;
current[now]=i;
if (dist[now]+1==dist[to]&&edge[i].flow>0&&
(f=dfs(to,min(flow,edge[i].flow),n))) {
edge[i].flow-=f;
edge[i^1].flow+=f;
return f;
}
}
return 0;
}

int dinic(int n) {
int sum=0,f;
while (bfs(n)) {
memcpy(current,head,sizeof(head));
while (f=dfs(0,inf,n)) sum+=f;
}
return sum;
}

int main() {
int cas,n,m,i,j,k;
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
scanf("%d",&cas);
while (cas--) {
num=0;
scanf("%d%d",&n,&m);
int final=n*m+1;
memset(head,-1,sizeof(head));
for (i=1;i<=n;i++)
scanf("%s",mp[i]+1);
for (i=1;i<=n;i++) {
for (j=1;j<=m;j++) {
int now=(i-1)*m+j;
if (mp[i][j]=='.') {
if (i==1||i==n||j==1||j==m)
addedge(0,now,(i==1)+(i==n)+(j==1)+(j==m));
for (k=0;k<4;k++) {
int nowx=i+dir[k][0],nowy=j+dir[k][1];
if (nowx>0&&nowx<=n&&nowy>0&&nowy<=m)
if (mp[nowx][nowy]!='X')
addedge(now,(nowx-1)*m+nowy,1);
}
}
if (mp[i][j]=='D') {
if (i==1||i==n||j==1||j==m)
addedge(0,final,(i==1)+(i==n)+(j==1)+(j==m));
addedge(now,final,4-((i==1)+(i==n)+(j==1)+(j==m)));
for (k=0;k<4;k++) {
int nowx=i+dir[k][0],nowy=j+dir[k][1];
if (nowx>0&&nowx<=n&&nowy>0&&nowy<=m)
if (mp[nowx][nowy]!='X')
addedge(now,(nowx-1)*m+nowy,1);
}
}
}
}
/* for (i=0;i<num;i++) {
cout << edge[i].from << ' ' << edge[i].to << ' ' << edge[i].flow << endl;
}*/
int ans=dinic(final);
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  网络流