4657: tower

来源:互联网 发布:汽车can网络是什么 编辑:程序博客网 时间:2024/05/16 15:30

4657: tower

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 59  Solved: 28
[Submit][Status][Discuss]

Description

Nick最近在玩一款很好玩的游戏,游戏规则是这样的:
有一个n*m的地图,地图上的每一个位置要么是空地,要么是炮塔,要么是一些BETA狗,Nick需
要操纵炮塔攻击BETA狗们。
攻击方法是:对于每个炮塔,游戏系统已经给出它可以瞄准的方向(上下左右其中一个),Nick需要
选择它的攻击位置,每一个炮塔只能够攻击一个位置,炮塔只能够向着它的瞄准方向上的某个位置发
动攻击,当然炮塔也可以不进行攻击。炮塔威力强大,它可以且仅可以消灭目标位置上所有的BETA狗。
出于安全考虑,游戏系统已经保证不存在一个炮塔能够瞄准另外一个炮塔,即对于任意一个炮
塔,它所有可能的攻击位置上不存在另外一个炮塔。而且,如果把炮塔的起点和终点称为炮弹的运行
轨迹,那么系统不允许两条轨迹相交f包括起点和终点)。
现在,选定目标位置以后,每一个炮塔同时开炮,你要告诉Nick,他最多可以干掉多少BETA狗。

Input

第一行两个正整数n,m,表示地图的规模。
接下来礼行,每行m个整数,0表示空地,-1,-2,一3,-4分别表示瞄准上下左右的炮塔,若为正整
数p,则表示该位置有p个BETA狗。
n,m <= 50,每个位置的BETA狗数量不超过999个,保证不存在任意一个炮塔能够瞄准另外一个炮塔

Output

一个正整数,表示Nick最多可以干掉几个BETA狗

Sample Input

3 2
0 9
-4 3
0 -1

Sample Output

9

HINT

Source

[Submit][Status][Discuss]



对于每个纵向发射的炮弹,定义它的方向是从炮台出发到目标

对于每个横向发射的炮弹,定义它的方向是从目标出发到炮台

考虑两条相交的炮弹轨迹,就能画成这样的形式

那么就可以看成一条x->y的路径

所以一个合法的方案必然不存在任何这样的路径

先将每条路径上最大的BETA狗数量统计出来,加起来作为答案

考虑使用最小割将不合法的路径剔除

对于一条有向边(u,v),如果割掉它,就当做让炮塔攻击了点u

那么每个纵向炮塔向出发的方向连边,每个横向炮塔向进入的方向连边

不过这样会出现一个小BUG

此图虽然出现了一条x->y的路径,但是有一个合法方案可以与之对应,即每个点都打到面前的板上

出现这种情况的原因,是这条路径连续拐了两个弯,那么不允许出现连续拐两个弯的局面

把原图中每个点拆成纵点和横点,每个纵点向对应的横点连INF的边

纵点和纵点之间,横点和横点之间再连边即可

#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<algorithm>#include<cmath>#include<stack>#define min(a,b) ((a) < (b) ? (a) : (b))#define max(a,b) ((a) > (b) ? (a) : (b))using namespace std; const int maxn = 5050;const int INF = ~0U>>1;const int maxm = 4E5 + 40;const int dx[4] = {-1,1,0,0};const int dy[4] = {0,0,-1,1}; struct E{    int to,cap,flow; E(){}    E(int to,int cap,int flow): to(to),cap(cap),flow(flow){}}edgs[maxm]; int n,m,tot,s,t,Ans,cnt,A[55][55],B[55][55],w[55][55],cur[maxn],L[maxn]; queue <int> Q;vector <int> v[maxn]; inline void Add(int x,int y,int cap){    v[x].push_back(cnt); edgs[cnt++] = E(y,cap,0);    v[y].push_back(cnt); edgs[cnt++] = E(x,0,0);} void Build(){    for (int i = 1; i <= n; i++)        for (int j = 1; j <= m; j++)        {            if (w[i][j] >= 0) continue;            int dir = -(w[i][j] + 1),Max = w[i][j] = 0;            for (int x = i + dx[dir],y = j + dy[dir]; ;)            {                if (x < 1 || x > n || y < 1 || y > m) break;                Max = max(Max,w[x][y]); x += dx[dir]; y += dy[dir];            }            Ans += Max;            if (dir <= 1)            {                Add(s,A[i][j],INF);                for (int x = i + dx[dir],y = j + dy[dir]; ;)                {                    if (x < 1 || x > n || y < 1 || y > m) break;                    Add(A[x - dx[dir]][y - dy[dir]],A[x][y],Max - w[x - dx[dir]][y - dy[dir]]);                    x += dx[dir]; y += dy[dir];                }            }            else            {                Add(B[i][j],t,INF);                for (int x = i + dx[dir],y = j + dy[dir]; ;)                {                    if (x < 1 || x > n || y < 1 || y > m) break;                    Add(B[x][y],B[x - dx[dir]][y - dy[dir]],Max - w[x - dx[dir]][y - dy[dir]]);                    x += dx[dir]; y += dy[dir];                }            }        }} inline bool BFS(){    for (int i = 1; i <= tot; i++) L[i] = 0;    L[s] = 1; Q.push(s);    while (!Q.empty())    {        int k = Q.front(); Q.pop();        for (int i = 0; i < v[k].size(); i++)        {            E e = edgs[v[k][i]];            if (e.cap == e.flow || L[e.to]) continue;            L[e.to] = L[k] + 1; Q.push(e.to);        }    }    return L[t];} inline int Dinic(int x,int a){    if (x == t) return a; int flow = 0;    for (int &i = cur[x]; i < v[x].size(); i++)    {        E &e = edgs[v[x][i]];        if (e.cap == e.flow || L[e.to] != L[x] + 1) continue;        int f = Dinic(e.to,min(a,e.cap - e.flow));        if (!f) continue; flow += f; e.flow += f;        edgs[v[x][i]^1].flow -= f; a -= f;        if (!a) return flow;    }    if (!flow) L[x] = -1; return flow;} int main(){    #ifdef DMC        freopen("DMC.txt","r",stdin);    #endif     cin >> n >> m;    for (int i = 1; i <= n; i++)        for (int j = 1; j <= m; j++)        {            A[i][j] = ++tot; B[i][j] = ++tot;            scanf("%d",&w[i][j]); Add(A[i][j],B[i][j],INF);        }    s = ++tot; t = ++tot; Build();         int MinCut = 0;    while (BFS())    {        for (int i = 1; i <= tot; i++) cur[i] = 0;        MinCut += Dinic(s,INF);    }    cout << Ans - MinCut << endl;    return 0;}

0 0