hdu2686 最大费用流

23 篇文章 0 订阅
5 篇文章 0 订阅

将边的cost取反 转换成求最小费用流的问题 得出结果再取反回来即可

具体的建图步骤在代码里有注释 写的很详细了。


Matrix

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2606    Accepted Submission(s): 1388


Problem Description
Yifenfei very like play a number game in the n*n Matrix. A positive integer number is put in each area of the Matrix.
Every time yifenfei should to do is that choose a detour which frome the top left point to the bottom right point and than back to the top left point with the maximal values of sum integers that area of Matrix yifenfei choose. But from the top to the bottom can only choose right and down, from the bottom to the top can only choose left and up. And yifenfei can not pass the same area of the Matrix except the start and end. 
 

Input
The input contains multiple test cases.
Each case first line given the integer n (2<n<30) 
Than n lines,each line include n positive integers.(<100)
 

Output
For each test case output the maximal values yifenfei can get.
 

Sample Input
  
  
2 10 3 5 10 3 10 3 3 2 5 3 6 7 10 5 1 2 3 4 5 2 3 4 5 6 3 4 5 6 7 4 5 6 7 8 5 6 7 8 9
 

Sample Output
  
  
28 46 80
 

Author
yifenfei
 


// Bellman_Ford
//Bellman—Ford算法
//Bellman算法求最短增广路&最小费用流 O(FEV)
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<stack>
#include<queue>
#include<cmath>
#include<stack>
#include<list>
#include<map>
#include<set>
typedef long long ll;
using namespace std;
#define MV 11000
#define INF 0x3f3f3f3f

struct edge
{
    int t, cap, cost, rev;
    edge(int to = 0, int c = 0, int ct = 0, int r = 0): t(to), cap(c), cost(ct), rev(r) {};
};
int a[32][32]; //save the map;
vector <edge> G[MV];
int dis[MV];
int prevv[MV], preve[MV];

void addedge(int s1,int t1,int cap,int cost)
{
    G[s1].push_back(edge(t1, cap, cost, G[t1].size()));
    G[t1].push_back(edge(s1, 0, -cost, G[s1].size() - 1));
}
int min_cost_flow(int v,int s, int t, int f)
{
    
    int ans = 0, i, j;
    while(f > 0)
    {
        fill(dis, dis + v, INF);
        dis[s] = 0;
        bool update = true;
        while(update)
        {
            update = false;
            for(i = 0; i < v; ++i)
            {
                int size1 = G[i].size();
                if(dis[i] == INF)
                    continue;
                for(j = 0; j < size1; ++j)
                {
                    edge &es = G[i][j];
                    if(es.cap > 0 && dis[es.t] > dis[i] + es.cost)
                    {
                        dis[es.t] = dis[i] + es.cost;
                        prevv[es.t] = i;
                        preve[es.t] = j;
                        update = true;
                    }
                }
            }
        }
        
        if(dis[t] == INF)
            return -1;
        int d = f;
        for(i = t; i != s; i = prevv[i])
            d = min(d, G[prevv[i]][preve[i]].cap);
        
        ans += d * dis[t];
        f -= d;
        for(i = t; i != s; i = prevv[i])
        {
            edge &es = G[prevv[i]][preve[i]];
            es.cap -= d;
            G[es.t][es.rev].cap += d;
        }
    }
    return ans;
}




int main()
{
    int  v, s, t, f;
    // v total number of node
    // s source  t sink
    // f  needed flow
    int i,j;
    int n;
    while(scanf("%d",&n)==1)
    {
        for(i=0;i<n;i++)
        {
            for(j=0;j<n;j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        for(i=0;i<MV;i++)
        {
            G[i].clear();
        }
        for(i=0;i<n;i++)
        {
            for(j=0;j<n;j++)
            {
                if(i==0&&j==0||i==n-1&&j==n-1)// 把左上角和右下角的点拆成两个点 权值设为2
                {
                        addedge(i*n+j, i*n+j+n*n, 2, 0);//自己与自己相连时 cost为0
                    
                }
                else
                {
                    addedge(i*n+j, i*n+j+n*n, 1, 0); //若不是左上角或者右下角的 设为1
                                                     //自己与自己相连时 cost为0
                }
                //下面两个if语句都是自己与自己右边和下边的点相连
                //这时 例如 b点在c的下边 那么从c连一条边指向b 权值是c点所在格子的值
                //就是说 从a[i][j]连出去的边 权值为a[i][j]
                if(i<n-1)
                {
                    addedge(i*n+j+n*n, (i+1)*n+j, 1, -a[i][j]);
                }
                if(j<n-1)
                {
                    addedge(i*n+j+n*n, i*n+j+1, 1, -a[i][j]);
                }
            }
        }
        
        s=0; //source
        t=(n-1)*n+n-1+n*n; //sink
        int tt=-min_cost_flow(1900,s, t, 2);
        
        //这时会发现 源点的值其实被加了两遍 汇点的值没有加过 所以要加上汇点的 减去多加的那次源点的
        tt+=a[n-1][n-1];
        tt-=a[0][0];
        printf("%d\n",tt);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值