Landscaping 最大流 / 最小割

Preparations for a good harvest in Spring start now and farmer John is preparing his field for a good season. He went over budget last year, as the tractors moving up and down the hills needed more fuel than he expected.

When harvesting, his tractors need to move both horizontally and vertically across all the land. In the image, you can see a region at low altitude in light green and a region at high altitude in dark green. When harvesting, his tractors will have to cross all the hills marked in red and they will have to go up or down 8 times.

This year, he is wondering whether he should level some parts of his field before sowing in order to lower his harvesting costs later on. Can you help him decide where the bulldozers should work in order to lower his costs? Farmer John knows that his tractors need A additional euros when moving between adjacent patches of land at different heights. He can also pay B euros to either increase or  decrease the height of any patch in his field.

What is the minimum amount of money he will have to pay this season?

Task

Given a description of the field, the price to change the height of a patch of land and the price his tractors pay when moving between adjacent patches, the goal is to find out the minimum amount that farmer John will have to pay this year.

Input

The first line consists of 4 space separated integers,

N,M,A and B.N and M represent  the dimensions of his N×M field, A represents the cost to move between adjacent patches of land at different levels and B is the cost to change any patch of land. Universidade do Porto Computer Science Department

The next N lines each have M characters and represent farmer John’s field. A ’.’ signals a patch of land at a low level and a ’#’ represents a patch of land at a high level.

Constraints 1 ≤ N, M ≤ 50 Size of the field. 1 ≤ A, B ≤ 100 000 Cost to change any height or to move between adjacent patches.

Output

You should output a single line with a single integer representing the minimum amount of money that farmer John will have to pay.

Sample Input

5 4 1000 2000

...#

#..#

...#

##..

###.

Sample Output

11000

題目大意:Farmer John 有一塊n*m的田地,他要用推土機推每一行和每一列。田地有高有低,相鄰的地高度不同就要付出a的代價,改動一塊地的高度需要付出b的代價。問 所要求的代價和的最小值。

解法:因爲是將田地分爲兩類,所以聯想到求最小割。

那麼如何建圖呢?

首先,設立一個源點s和一個匯點t。讓所有低地和s連一條代價爲b的邊,所有高地和t連一條代價爲b的邊。 此時高地和低地之間是不相連的,最小割,也就是最大流等於零。

然後將所有 位置相鄰 且 高低不同 的地之間連一條代價爲a的邊。

如圖,在求最小割的時候,要麼把高低地之間的邊割掉,要麼把地和源點/匯點之間的邊割掉。

這樣原圖的最小割就等同於將其中一些土地的高度改動的代價和相鄰高度 不等的土地之間的代價總和的最小值了。

代碼:

#include<iostream>
#include<cstdio>
#include<string.h>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;

const  int maxv=1e4+10,  INF=1e9+10;
const int dx[4]={-1, 0, 1, 0},
            dy[4]={0, -1, 0, 1};

struct edge{ int to;  int  cap;  int rev;};
vector<edge> G[maxv];
int level[maxv],iter[maxv];
bool used[maxv];

void add_edge( int from, int to,  int cap)
{
    G[from].push_back((edge){to, cap, G[to].size()});
    G[to].push_back((edge){from, 0, G[from].size()-1});
}

void bfs( int s){
    memset(level, -1, sizeof(level));
    queue<int> que;
    level[s]=0;
    que.push(s);
    while (!que.empty())
    {
         int v=que.front();
        que.pop();
        for ( int i=0; i<G[v].size(); i++)
        {
            edge &e=G[v][i];
            if (e.cap > 0 && level[e.to] < 0)
            {
                level[e.to] = level[v] + 1;
                que.push(e.to);
            }
        }
    }
}

int dfs( int v,  int t,   int  f)
{
    if (v==t) return f;
    for ( int &i=iter[v]; i<G[v].size(); i++)
    {
        edge &e=G[v][i];
        if (e.cap > 0 && level[v] < level[e.to]){
             int  d=dfs(e.to, t, min(f, e.cap));
            if (d>0){
                e.cap -= d;
                G[e.to][e.rev].cap+=d;
                return d;
            }            
        }
    }    
    return 0;
}

 long long  max_flow( int s, int t){
     long long  flow=0;
    for (;;){
        bfs(s);
        if (level[t]<0) return flow;
        memset(iter, 0, sizeof(iter));
         int  f;
        while ((f = dfs(s,t,INF))>0)
        flow += (long long)f;
    }
}

bool f[500][500];
int main()
{
     int n,m,s,t;
     long long  a,b;
    char ss[500];

    cin>>n>>m>>a>>b;   //a是相鄰高度不同的代價,b是修改的代價
    
    s=n*m+1;                       //s代表低地集合
    t=s+1;                       //t代表高地集合
    for ( int  i=0; i<n; i++)
    {
        scanf("%s", &ss);
        for ( int j=0; j<m; j++)
        {
            if (ss[j]=='.')            //是一塊低地  
            {
                f[i][j]=0;
                add_edge(s, i*m+j, b);    //低地和s連邊
            }
            else                   //是一塊高地
            {
                f[i][j]=1;
                add_edge(i*m+j, t, b);    //高地和t連邊
            }
        }
    }

    for ( int  i=0; i<n; i++)
    {
        for ( int  j=0; j<m; j++)
        {
            for (int k=0; k<4; k++)
            {
                int x=i+dx[k],y=j+dy[k];
                if (x>=0  && x<n && y>=0 && y<m)
                {
                    add_edge(i*m+j,  x*m+y , a);
                }
            }
        }
    }

    cout<<max_flow(s, t);

    return 0;
}

 

剛開始在建邊的時候採取了用當前土地與左邊的土地  和 上邊的土地比較,然後建雙向邊的辦法。不知道爲什麼WA了,後來改成將當前土地和上下左右相比較,建單向邊的辦法,就A了。= =

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章