joj 2724: Hua Rong Dao 最小割

2724 Hua Rong Dao

I guess you are fond of playing San Guo Sha, right? So here comes a problem of San Guo. It‟s 
a famous story – “Hua Rong Dao”.

In order to help Cao Cao to escape, the soldiers of Cao Cao have been divided into several
parts, and Cao Cao is in one of these part. Now they are all in a rectangle area which can be
divided into many squares of the equal size. Once the soldiers get out of this area, they escape
successfully.

Because Liu Bei and Sun Quan don't know exactly which part Cao Cao is in, they decided to
catch all Cao Cao's soldiers.

In this area, some squares are lawns that can be passed, while some others are Marshes that
can't be passed. Liu Bei and Sun Quan decide to set fire on lawns to those squares that cannot
be passed. Owing to some reasons, setting fire on different squares needs different length of
time. And they can only set fire on one square at the same time. Now, Cao Cao and all his
soldiers are having rest and you can assume that they won't move. Liu Bei and SunQuan
want to know how much time they need at least to set fire to make Cao Cao and all his
soldiers can't escape in whatever way when they want to move. Can you help them?

Input

The first line in the input file is a single integer: T (1 ≤ T ≤ 10), representing the number of test 
cases. For each test case, in the first line there are two integers: r and c (1 ≤ r, c ≤ 30) - the
height and length of the area. Then there are r lines, in each line there are c integers. The j-th
integer in the i-th line is m  . Each of these integers describes a square: if t           is positive, then the
                                ij                                                       ij

square is a lawn and it needs mij unit of time to set fire on it; if mij  is 0, it means some soldiers
of Cao Cao are having rest in this square; if mij  is -1, means the square can't be passed.

When Cao Cao and his soldiers move, they can only move to a square that share an edge with
the square they are in just now. All positive integers in the input file are smaller or equal to
100.

Output

For each test case, output a single integer, means the number of unit of time Liu Bei and Sun
Quan need to set fire so that Cao Cao and his soldiers can't get escape.

It is guaranted that the answer is exists.

Sample Input

1

4 3
   1 2 1
1 10 1
1 0 -1
   1 1 1

Sample Output

6

                                                                     

 

 //

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2010;
const int M=550000;//500000 不够
const int inf=(1<<28);
int head[N];
struct Edge
{
    int u,v,next,w;
} edge[M];
int cnt,n,s,t;//n从0开始  0->n-1
void addedge(int u,int v,int w)
{
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt++;
    edge[cnt].u=v;
    edge[cnt].v=u;
    edge[cnt].w=0;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}
int sap()
{
    int pre[N],cur[N],dis[N],gap[N];
    int flow=0,aug=inf,u;
    bool flag;
    for(int i=0; i<n; i++)
    {
        cur[i]=head[i];
        gap[i]=dis[i]=0;
    }
    gap[s]=n;
    u=pre[s]=s;
    while(dis[s]<n)
    {
        flag=0;
        for(int &j=cur[u]; j!=-1; j=edge[j].next)
        {
            int v=edge[j].v;
            if(edge[j].w>0&&dis[u]==dis[v]+1)
            {
                flag=1;
                if(edge[j].w<aug) aug=edge[j].w;
                pre[v]=u;
                u=v;
                if(u==t)
                {
                    flow+=aug;
                    while(u!=s)
                    {
                        u=pre[u];
                        edge[cur[u]].w-=aug;
                        edge[cur[u]^1].w+=aug;
                    }
                    aug=inf;
                }
                break;
            }
        }
        if(flag) continue;
        int mindis=n;
        for(int j=head[u]; j!=-1; j=edge[j].next)
        {
            int v=edge[j].v;
            if(edge[j].w>0&&dis[v]<mindis)
            {
                mindis=dis[v];
                cur[u]=j;
            }
        }
        if((--gap[dis[u]])==0)
            break;
        gap[dis[u]=mindis+1]++;
        u=pre[u];
    }
    return flow;
}

//初始化  cnt=0;memset(head,-1,sizeof(head));
int xx[4]={0,0,1,-1};
int yy[4]={1,-1,0,0};
int a[50][50];
//最小割+拆点
int main()
{
    int ci;scanf("%d",&ci);
    while(ci--)
    {
        int m,p;scanf("%d%d",&m,&p);
        int num=m*p;
        for(int i=1;i<=m;i++) for(int j=1;j<=p;j++) scanf("%d",&a[i][j]);
        n=num*2+2;
        s=0,t=n-1;
        cnt=0;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=p;j++)
            {
                int pos=(i-1)*p+j;
                if(a[i][j]==-1)
                {
                }
                else if(a[i][j]>0)
                {
                    addedge(pos,pos+num,a[i][j]);
                }
                else
                {
                    addedge(s,pos,inf);
                    addedge(pos,pos+num,inf);
                }
                for(int k=0;k<4;k++)
                {
                    int x=i+xx[k],y=j+yy[k];
                    if(x>=1&&x<=m&&y>=1&&y<=p)
                    {
                        int pos2=(x-1)*p+y;
                        addedge(pos+num,pos2,inf);
                    }
                }
                if(i==1||i==m||j==1||j==p)//边界
                {
                    addedge(pos+num,t,inf);
                }
            }
        }
        int ans=sap();
        printf("%d\n",ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值