[TJOI2009]战争游戏 - 网络流,最小割
Posted nishikino-curtis
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[TJOI2009]战争游戏 - 网络流,最小割相关的知识,希望对你有一定的参考价值。
Description
小R正在玩一个战争游戏。游戏地图是一个M行N列的矩阵,每个格子可能是障碍物,也可能是空地,在游戏开始时有若干支敌军分散在不同的空地格子中。每支敌军都可以从当前所在的格子移动到四个相邻的格子之一,但是不能移动到包含障碍物的格子。如果敌军移动出了地图的边界,那么战争就失败了。
现在你的任务是,在敌军开始移动前,通过飞机轰炸使得某些原本是空地的格子变得不可通行,这样就有可能阻止敌军移出地图边界(出于某种特殊的考虑,你不能直接轰炸敌军所在的格子)。由于地形不同的原因,把每个空地格子轰炸成不可通行所需的Bomb数目可能是不同的,你需要计算出要阻止敌军所需的最少的Bomb数。
Input & Output
Input
输入文件的第一行包含两个数M和N,分别表示矩阵的长和宽。接下来M行,每行包含用空格隔开的N个数字,每个数字表示一个格子的情况:若数字为-1,表示这个格子是障碍物;若数字为0,表示这个格子里有一支敌军;若数字为一个正数x,表示这个格子是空地,且把它轰炸成不可通行所需的Bomb数为x。
Output
输出一个数字,表示所需的最少Bomb数。数据保证有解存在。
Sample
Input
4 3
1 2 1
1 10 1
1 0 -1
1 1 1
Output
6
Solution
把每个可轰炸的点拆点,由i向i + ?连一条容量为点权的边,特别地,对于敌军所在的点,由源点向敌军,敌军向拆点各连一条INF,然后在所有非障碍的四连通格子间连双向INF,具体的操作是x -> y + ?, y -> x + ?,最后是所有非障碍边界向汇点连一条INF,这里说的边都包括了对应的反向弧。
求最小割即可。
Code:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using std::memset;
using std::min;
using std::max;
using std::swap;
using std::cin;
using std::cout;
using std::endl;
using std::ios;
using std::queue;
const int maxn = 64;
const int INF = 0x3f3f3f3f;
struct edge
{
int to,nxt,v;
}e[10005];
int n,m,s,t,lnk[10005],level[10005],ptr;
int mtr[32][32],num[32][32];
void add(int bgn,int end,int flow)
{
e[ptr].v = flow; e[ptr].to = end; e[ptr].nxt = lnk[bgn]; lnk[bgn] = ptr; ++ptr;
e[ptr].v = 0; e[ptr].to = bgn; e[ptr].nxt = lnk[end]; lnk[end] = ptr; ++ptr;
}
bool bfs()
{
queue<int> q;
memset(level,0,sizeof(level));
level[s]=1;
q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
for(int p=lnk[u]; ~p; p=e[p].nxt){
int y=e[p].to;
if(e[p].v > 0 && !level[y]){
level[y]=level[u]+1;
q.push(y);
}
}
}
if(level[t]==0) return false;
else return true;
}
int dfs(int x,int fl)
{
if(x==t)return fl;
for(int p=lnk[x]; ~p; p=e[p].nxt){
int y=e[p].to;
if(level[y]==level[x]+1&&e[p].v!=0){
int delta=dfs(y,min(fl,e[p].v));
if(delta > 0){
e[p].v-=delta;
e[p^1].v+=delta;
return delta;
}
}
}
return 0;
}
int dinic()
{
int ret=0;
while(bfs()){
while(int delta=dfs(s,INF))
ret+=delta;
}
return ret;
}
int main()
{
ios::sync_with_stdio(false);
memset(lnk,-1,sizeof(lnk));
cin >> n >> m;
t = n*m; s = 0;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
cin >> mtr[i][j];
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
{
num[i][j] = i * m + j;
if(mtr[i][j])add(num[i][j],num[i][j] + t,mtr[i][j]);
}
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j)
{
if(mtr[i][j] == 0) add(s,num[i][j],INF) , add(num[i][j], num[i][j] + t, INF);
if(i > 1 && mtr[i-1][j] >= 0 && mtr[i][j] >= 0)
add(num[i][j] + t, num[i-1][j], INF),
add(num[i-1][j] + t, num[i][j], INF);
if(j > 1 && mtr[i][j-1] >= 0 && mtr[i][j] >= 0)
add(num[i][j] + t, num[i][j-1], INF),
add(num[i][j-1] + t, num[i][j], INF);
if(i == 1 || i == n || j == 1 || j == m)
add(num[i][j] + t, (t << 1) + 1, INF);
}
t = (t << 1) + 1;
cout << dinic() << endl;
return 0;
}
辣鸡博客园居然还有Bomb这种敏感词
以上是关于[TJOI2009]战争游戏 - 网络流,最小割的主要内容,如果未能解决你的问题,请参考以下文章
[bzoj4554] [Tjoi2016&Heoi2016]游戏
[2016北京集训试题6]网络战争-[最小割树(网络流)+kd-tree+倍增]