The Great Wall I (zoj 3475 最小割最大流)

46 篇文章 0 订阅

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 afford, i, j (-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

Author: WANG, Yelei
Contest: ZOJ Monthly, February 2011

题意:n*m的地图,现在上面有X国家和一些联盟国要共同抵御E国,X国要建长城,有一些国家联盟进来并出一定费用,每条边都有一个建造费用,告诉每个国家的坐标和参加联盟的国家出的费用,问X国怎样建可以使费用最小,输出最小费用。

思路:这一类题目在图中把点分成两部分可以用最小割求解,图中的一条边就表示以改变为公共边的两个点之间有弧,添加源点和汇点,枚举哪些国家在长城内,将源点与这些国家连边,E和边界与汇点连边。这样求一遍最大流,选择了某条边为割边就表示方格中两个格子间的那条围墙被选择了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define mod 1000000009
#define INF 1000000
#define pi acos(-1.0)
#define eps 1e-6
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define FRE(i,a,b)  for(i = a; i <= b; i++)
#define FREE(i,a,b) for(i = a; i >= b; i--)
#define FRL(i,a,b)  for(i = a; i < b; i++)
#define FRLL(i,a,b) for(i = a; i > b; i--)
#define mem(t, v)   memset ((t) , v, sizeof(t))
#define sf(n)       scanf("%d", &n)
#define sff(a,b)    scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf          printf
#define DBG         pf("Hi\n")
typedef long long ll;
using namespace std;

const int MAXN = 450;
const int MAXM = 200000;

int n,m;
struct Edge
{
    int to,next,cap,flow;
}edge[MAXM],E[MAXM];

int tol;
int head[MAXN],hed[MAXN];
int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];

void init()
{
    tol=0;
    memset(head,-1,sizeof(head));
}

//加边,单向图三个参数,双向图四个参数
void addedge(int u,int v,int w,int rw=0)
{
    edge[tol].to=v; edge[tol].cap=w; edge[tol].next=head[u];
    edge[tol].flow=0; head[u]=tol++;
    edge[tol].to=u; edge[tol].cap=rw; edge[tol].next=head[v];
    edge[tol].flow=0; head[v]=tol++;
}

//输入参数:起点,终点,点的总数
//点的编号没有影响,只要输入点的总数
int sap(int start,int end,int N)
{
    memset(gap,0,sizeof(gap));
    memset(dep,0,sizeof(dep));
    memcpy(cur,head,sizeof(head));
    int u=start;
    pre[u]=-1;
    gap[0]=N;
    int ans=0;
    while (dep[start]<N)
    {
        if (u==end)
        {
            int Min=INF;
            for (int i=pre[u];i!=-1;i=pre[edge[i^1].to])
                if (Min>edge[i].cap-edge[i].flow)
                    Min=edge[i].cap-edge[i].flow;
            for (int i=pre[u];i!=-1;i=pre[edge[i^1].to])
            {
                edge[i].flow+=Min;
                edge[i^1].flow-=Min;
            }
            u=start;
            ans+=Min;
            continue;
        }
        bool flag=false;
        int v;
        for (int i=cur[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].to;
            if (edge[i].cap-edge[i].flow && dep[v]+1==dep[u])
            {
                flag=true;
                cur[u]=pre[v]=i;
                break;
            }
        }
        if (flag)
        {
            u=v;
            continue;
        }
        int Min=N;
        for (int i=head[u];i!=-1;i=edge[i].next)
            if (edge[i].cap-edge[i].flow && dep[edge[i].to]<Min)
            {
                Min=dep[edge[i].to];
                cur[u]=i;
            }
        gap[dep[u]]--;
        if (!gap[dep[u]]) return ans;
        dep[u]=Min+1;
        gap[dep[u]]++;
        if (u!=start) u=edge[pre[u]^1].to;
    }
    return ans;
}

int getid(int x,int y)
{
    return x*m+y;
}

int X[MAXN],Y[MAXN],afford[MAXN];
int mp[MAXN][MAXN];

int main()
{
#ifndef ONLINE_JUDGE
    freopen("C:/Users/asus1/Desktop/IN.txt","r",stdin);
#endif
    int i,j,cost;
    while (~sff(n,m))
    {
        init();
        int ss=n*m,tt=ss+1;
        for (i=0;i<=n;i++)
        {
            for (j=0;j<m;j++)
            {
                sf(cost);
                if (i==0)
                    addedge(tt,getid(i,j),cost,cost);
                else if (i==n)
                    addedge(getid(i-1,j),tt,cost,cost);
                else
                    addedge(getid(i,j),getid(i-1,j),cost,cost);
            }
            if (i==n) break;
            for (j=0;j<=m;j++)
            {
                sf(cost);
                if (j==0)
                    addedge(tt,getid(i,j),cost,cost);
                else if (j==m)
                    addedge(getid(i,j-1),tt,cost,cost);
                else
                    addedge(getid(i,j),getid(i,j-1),cost,cost);
            }
        }
        int K;
        sf(K);
        for (i=0;i<K;i++)
        {
            sfff(afford[i],X[i],Y[i]);
            if (afford[i]<0)
            {
                addedge(getid(X[i],Y[i]),tt,INF,INF);
                i--;K--;
            }
            else if (afford[i]==0)
            {
                swap(X[0],X[i]);
                swap(Y[0],Y[i]);
                swap(afford[0],afford[i]);
            }
        }
        int ans=INF;
        int tmp=tol;
        memcpy(E,edge,sizeof(edge));
        memcpy(hed,head,sizeof(head));
        for (i=1;i<(1<<K);i+=2)
        {
            int x=0;
            memcpy(edge,E,sizeof(E));
            memcpy(head,hed,sizeof(hed));
            tol=tmp;
            for (j=0;j<K;j++)
            {
                if ((1<<j)&i)
                {
                    addedge(ss,getid(X[j],Y[j]),INF,INF);
                    x-=afford[j];
                }
            }
            x+=sap(ss,tt,n*m+2);
            ans=min(ans,x);
        }
        pf("%d\n",ans);
    }
    return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值