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 thecost (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 negetiveafford means that the country is aggressive. A zeroafford 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

原题链接

 题意:n*m的地图,现在上面有X国家和一些联盟国要共同抵御E国,X国要建长城,有一些国家联盟进来并出一定费用,

            每条边都有一个建造费用,告诉每个国家的坐标和参加联盟的国家出的费用,问X国怎样建可以使费用最小,输出最小费用。

分析:最小城墙费用 来阻碍一些点到另一些点,思考时应该想到这个模型(最小割)(当时想不出来,参考大佬博客)。

            建立一个源点,连接需要保护的国家,容量为INF, 建立一个汇点,把所有的敌国和边界连接到汇点。其他相邻

            两点建双向边,容量为城墙造价。最大流即使最小割,即是城墙费用。然后枚举需要保护的国家(一般用二 进 制)

            求出最低的成本。

附上代码

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
struct edge
{
    int to,cap,rev;
    edge(int x,int y,int z)
    {
        to=x;cap=y;rev=z;
    }
};
vector<edge> g[666],og[666];
int level[666],iter[666],n,m,s,sum,a[111][2];
bool vis[666];
void add(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 init()
{
    for(int i=0;i<=n;i++)
        g[i].clear();
}
void bfs(int s)
{
    memset(level,-1,sizeof(level));
    level[s]=0;
    queue<int> que;
    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[e.to]>level[v])
        {
            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;
}
int max_flow(int s,int t)
{
    int flow=0;
    while(1)
    {
        bfs(s);
        if(level[t]<0)return flow;
        memset(iter,0,sizeof(iter));
        int  f;
        while(f=dfs(s,t,INF))
        {
            flow+=f;
        }
    }
}
int get(int x,int y)
{
    return x*m-m+y;
}
int main()
{
    int x,y,z;
    while(scanf("%d%d",&n,&m)!=EOF)
    {int s=0,t=n*m+1;
        for(int i=0;i<=t;i++)
            g[i].clear();

       for(int i=0;i<=n;i++)
       {
           for(int j=1;j<=m;j++)
           {    scanf("%d",&x);
           //cout<<" *** "<<x<<"  ";
               if(i==0)
                  add(get(i+1,j),t,x);
               else if(i==n)
                   add(get(i,j),t,x);
               else
                {
                    add(get(i,j),get(i+1,j),x);
                    add(get(i+1,j),get(i,j),x);
                }
           }
           if(i==n)continue;
           for(int j=0;j<=m;j++)
           {
               scanf("%d",&x);
               //cout<<"  &&& "<<x<<"  ";
               if(j==0)
                add(get(i+1,j+1),t,x);
               else if(j==m)
                add(get(i+1,j),t,x);
               else
               {
                   add(get(i+1,j),get(i+1,j+1),x);
                   add(get(i+1,j+1),get(i+1,j),x);
               }
           }
       }
       int xx,tot=0;
       scanf("%d",&xx);
       for(int i=1;i<=xx;i++)
       {
           scanf("%d%d%d",&z,&x,&y);
           x++;y++;
           if(z>0)
           {
               a[tot][0]=get(x,y);
               a[tot][1]=z;
               tot++;
           }
           else if(z==0)
           {
               add(s,get(x,y),INF);
           }
           else
           {
               add(get(x,y),t,INF);
           }
       }
       int ss=1<<tot,cut,mixx=INF;//cout<<max_flow(s,t)<<endl;
       for(int i=0;i<=t;i++)
       {
           og[i].clear();
           for(int j=0;j<g[i].size();j++)
            og[i].push_back(g[i][j]);
       }

       for(int l=0;l<ss;l++)
       {
           cut=0;
         for(int i=0;i<=t;i++)
       {
           g[i].clear();
           for(int j=0;j<og[i].size();j++)
           g[i].push_back(og[i][j]);
       }
            for(int i=0;i<tot;i++)
            {
                if(l&(1<<i))
                {
                    cut-=a[i][1];
                    add(s,a[i][0],INF);
                }
            }

            int ans=max_flow(s,t);
            //cout<<ans;
            cut+=ans;
            if(cut<mixx)
                mixx=cut;
       }
       printf("%d\n",mixx);
    }
    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值