ZOJ 3475 The Great Wall I

The Great Wall I

Time Limit: 2 Seconds       Memory Limit: 65536 KB

Long long ago, in the forgotten land, there is a rich country named X. There were several countries in the forgotten land and some of them were so aggressive that they often invade other countries, including X. X was so rich but its army was not strong enough to beat these invaders totally. So, the king of country X decided to build a national defense system to prevent the attack from other countries. The main part of the system is the great wall!

As far as the king knew, the map of the forgotten land is a rectangle with n * m grids, and each country occupied a single grid.

Some allied countries nearby want to join the system and were willing to pay some money for it to prevent themselves from the attack from those aggressive countries.

Now, knowing how much money each country was willing to pay and the cost to build wall at each board, the king must decide which countris are accepted to make the total cost at low at possible.

If a country has been accepted to join in the defense system, it will be safe when the great wall is done. Safe means that it's impossible to invade the country without destroying some part of the great wall from those aggressive countries (maybe some unknown country from the outside of the map).

For example, in the above map, X means country X, E means the aggressive country and A means the allied country. The cost to build great wall along each red border is 1 million doller and the cost to build great wall along each black border is 10 million doller. If the allied country afford more than 8 million doller, the best way is to build the great wall along the yellow curve. But if it cannot afford 8 million doller for the great wall, the best way is to build the great wall along the bule curve, just surrounding X.

Input

There are about a hundred cases.

  • The first line of each cases were two integer numbers N, M (1 <= N, M <= 20).
  • Then 2 * N + 1 lines followed, the jth integer of the (2 * i)th line is the cost to build great wall on the border between gird(i - 1, j) and grid(i, j) while the jth integer of the (2 * i + 1)th line is the cost (0 < cost <= 10000)of building great wall on the border between gird(i, j - 1) and grid(i, j).
  • The 2 * N + 2th line contains a single integer K(1 <= K <= 6)
  • The K lines followed, each line contains three integers affordij (-1 <= afford <= 10000, 0 <= i < N, 0 <= j < M), means the country in the grid(i, j) want to pay X afford money to the great wall. A negetive afford means that the country is aggressive. A zero afford means the country is X.
  • There will be one a only one country with zero afford in each case.
Output

A single integer, the minimum cost. Note that the cost can be negative when country X can earn money from the building of the great wall. .

Sample Input
3 3
1 1 1
1 10 10 1
10 1 10
1 1 1 1
10 1 10
1 10 10 1
1 1 1
3
0 0 0
-1 1 1
100 2 2

3 3
1 1 1
1 10 10 1
10 1 10
1 1 1 1
10 1 10
1 10 10 1
1 1 1
3
0 0 0
-1 0 1
9 2 2
Sample Output
-84
21
 
题意:在一个大陆上,有一个国家X,也有一些国家E,有国家X的同盟国A,X和A为了抵挡E的进攻,决定建造城墙来和国家E隔开,求建造这些城墙的最
小值。用图论的知识来理解就是将X和A为一个U集合,E为一个V集合,然后如果要将U和V隔开,就是求U和V之间的“桥”的权值,也就是求这个图的最小
割。然后最小割问题等价于求该网络的最大流,那么只要根据题目给出的边的权值即费用来构造网络,跑一遍Dinic之类就可以了。
这道题的输入有点恶心~~首先输入n和m,表示这个图的大小,接下来有2*n+1行,奇数行有m个数,表示横着的边权值,偶数行有m+1个数,表示竖着的
边的权值,然后输入k,表示有k个国家的信息,输入c,a,b,c=0表示国家X,c>0表示同盟国,c=-1表示国家E,只有c大于0的时候表示该国家愿意支付
的城墙费用,最后求国家X如果要建造城墙所花费的费用。
 
代码:
#include<cstring>
#include<cstdio>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;

struct Edge{
    int u,v,c,next;
};

int cost;
int n,m,k,s,t;
int sum;
int cst[4005];
Edge edge[4005];
int level[4005];
int head[4005];
int ne;

void add(int u,int v,int w){
    edge[ne].u=u;
    edge[ne].v=v;
    edge[ne].c=w;
    edge[ne].next=head[u];
    head[u]=ne++;

    edge[ne].u=v;
    edge[ne].v=u;
    edge[ne].c=0;
    edge[ne].next=head[v];
    head[v]=ne++;
}

void input(){
    memset(head,-1,sizeof(head));
    t=4003;
    sum=0;
    n+=2,m+=2;
    ne=0;
    for(int i=0;i<=n-2;i++)
    {
        int tmp;
        for(int j=2;j<=m-1;j++)
        {
            scanf("%d",&tmp);
            int u=i*m+j;
            int v=(i+1)*m+j;
            add(u,v,tmp);
            add(v,u,tmp);
        }
        if(i==n-2)
            break;
        for(int j=2;j<=m;j++)
        {
            scanf("%d",&tmp);
            int u=(i+1)*m+j;
            int v=(i+1)*m+j-1;
            add(u,v,tmp);
            add(v,u,tmp);
        }
    }
    scanf("%d",&k);
    int tv[10],tu[10];
    for(int i=1;i<=k;i++)
    {
        int x,y;
        scanf("%d%d%d",&tv[i],&x,&y);
        x+=2,y+=2;
        tu[i]=(x-1)*m+y;
        if(tv[i]==0)
            s=tu[i];
    }
    for(int i=1;i<=k;i++)
    {
        if(tv[i]==-1)
            add(tu[i],t,INF);
        else if(tv[i]>0)
        {
            sum+=tv[i];
            add(s,tu[i],tv[i]);
        }
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        if(i==1||i==n||j==1||j==m)
          add((i-1)*m+j,t,INF);
}

int BFS(){
    memset(level,0,sizeof(level));
    queue<int> q;
    q.push(s);
    level[s]=1;
    while(q.empty()==0){
        int u=q.front();
        q.pop();
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].c>0&&level[v]==0){
                level[v]=level[u]+1;
                q.push(v);
            }
        }
    }
    return level[t];
}
int DFS(int u,int Max){
    int ans=0;
    if(u==t){
        return Max;
    }
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(edge[i].c>0&&level[u]+1==level[v]){
            int Min=min(Max-ans,edge[i].c);
            int f=DFS(v,Min);
            if(f==0){
                level[v]=0;
            }
            else{
                edge[i].c-=f;
                edge[i^1].c+=f;
                ans+=f;
            }
            if(ans==Max){
                return ans;
            }
        }
    }
    return ans;
}

int Dinic(){
    int ans=0;
    while(BFS()){
        ans+=DFS(s,INF);
    }
    return ans;
}

int main(){
    while(~scanf("%d%d",&n,&m)){
        input();
        printf("%d\n",Dinic()-sum);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值