[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这种敏感词
相关推荐
henryzhihua 2020-06-10
深圳湾 2018-05-18
那些年那些有趣的数学 2018-01-12
天文八卦学 2018-01-04
爱燃烧最专业的中文跑步运动社区 2017-12-28