P3866 [TJOI2009]战争游戏

P3866 [TJOI2009]战争游戏

题目背景
小R正在玩一个战争游戏。游戏地图是一个M行N列的矩阵,每个格子可能是障碍物,也可能是空地,在游戏开始时有若干支敌军分散在不同的空地格子中。每支敌军都可以从当前所在的格子移动到四个相邻的格子之一,但是不能移动到包含障碍物的格子。如果敌军移动出了地图的边界,那么战争就失败了。

题目描述
现在你的任务是,在敌军开始移动前,通过飞机轰炸使得某些原本是空地的格子变得不可通行,这样就有可能阻止敌军移出地图边界(出于某种特殊的考虑,你不能直接轰炸敌军所在的格子)。由于地形不同的原因,把每个空地格子轰炸成不可通行所需的炸弹数目可能是不同的,你需要计算出要阻止敌军所需的最少的炸弹数。

输入输出格式
输入格式:
输入文件的第一行包含两个数M和N,分别表示矩阵的长和宽。接下来M行,每行包含用空格隔开的N个数字,每个数字表示一个格子的情况:若数字为-1,表示这个格子是障碍物;若数字为0,表示这个格子里有一支敌军;若数字为一个正数x,表示这个格子是空地,且把它轰炸成不可通行所需的炸弹数为x。

输出格式:
输出一个数字,表示所需的最少炸弹数。数据保证有解存在。


挺裸的最小割模型: 炸掉一个点 = 割掉一条边
这条关键边要放在哪呢? 一个点被炸掉了以后, 这个点再也不能通过, 联想到将点分裂为两个, 关建边容量为摧毁炸弹数连接这两个点。
所以我们做如下连边:
对于一点 \(x\) , 若是起点, 则连接源点与 \(x\) ,容量为 \(INF\) , 再连接 \(x\)\(x'\) 代表此点无法被轰炸
若是路障, 则连接 \(x\)\(x'\) 容量为 \(0\) , 表示此点不需要炸弹也走不通(即需要炸弹数为 \(0\)
其余则连接 \(x\)\(x'\) 容量为轰炸所需炸弹数即可

对于相连的两点, 连接出点与入点, 容量为 \(INF\)
对于边缘点, 连接出点与汇点, 容量为 \(INF\)

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
typedef long long LL;
using namespace std;
int RD(){
    int out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const int maxn = 1000019,INF = 1e9 + 19;
int head[maxn],nume = 1;
struct Node{
    int v,dis,nxt;
    }E[maxn << 3];
void add(int u,int v,int dis){
    E[++nume].nxt = head[u];
    E[nume].v = v;
    E[nume].dis = dis;
    head[u] = nume;
    }
int maxflow, s, t;
int d[maxn];
bool bfs(){
	queue<int>Q;
	memset(d, 0, sizeof(d));
	d[s] = 1;
	Q.push(s);
	while(!Q.empty()){
		int u = Q.front();Q.pop();
		for(int i = head[u];i;i = E[i].nxt){
			int v = E[i].v;
			if(!d[v] && E[i].dis)d[v] = d[u] + 1, Q.push(v);
			if(v == t)return 1;
			}
		}
	return 0;
	}
int Dinic(int u, int flow){
	if(u == t)return flow;
	int rest = flow, k;
	for(int i = head[u];i;i = E[i].nxt){
		int v = E[i].v;
		if(d[v] == d[u] + 1 && E[i].dis){
			k = Dinic(v, min(rest, E[i].dis));
			if(!k)d[v] = 0;
			E[i].dis -= k;
			E[i ^ 1].dis += k;
			rest -= k;
			}
		if(!rest)break;
		}
	return flow - rest;
	}
int lenx, leny;
int mx[4] = {0 ,0, 1,-1};
int my[4] = {1,-1, 0, 0};
int map[119][119];
int id(int x, int y){return (x - 1) * leny + y;}
bool judge(int x, int y){
	if(x < 1 || x > lenx || y < 1 || y > leny)return 0;
	return 1;
	}
int main(){
	lenx = RD();leny = RD();
	s = 0, t = 10026;
	for(int i = 1;i <= lenx;i++)for(int j = 1;j <= leny;j++)map[i][j] = RD();
	for(int i = 1;i <= lenx;i++)for(int j = 1;j <= leny;j++){
		int u = id(i, j);
		if(!map[i][j]){
			add(s, u << 1, INF), add(u << 1, s, 0);
			add(u << 1, u << 1 | 1, INF), add(u << 1 | 1, u << 1, 0);
			}
		else if(map[i][j] == -1)add(u << 1, u << 1 | 1, 0), add(u << 1 | 1, u << 1, 0);
		else add(u << 1, u << 1 | 1, map[i][j]), add(u << 1 | 1, u << 1, 0);
		for(int k = 0 ;k < 4;k++){
			int nx = i + mx[k];
			int ny = j + my[k];
			int v = id(nx, ny);
			if(judge(nx, ny)){
				add(u << 1 | 1, v << 1, INF);
				add(v << 1, u << 1 | 1, 0);
				}
			else add(u << 1 | 1, t, INF), add(t, u << 1 | 1, 0);
			}
		}
	int flow = 0;
	while(bfs())while(flow = Dinic(s, INF))maxflow += flow;
	printf("%d\n", maxflow);
	return 0;
	}
posted @ 2018-08-16 12:38  Tony_Double_Sky  阅读(182)  评论(0编辑  收藏  举报