hdu2686 最大费用流

来源:互联网 发布:网络信贷 编辑:程序博客网 时间:2024/05/22 20:15

将边的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
210 35 10310 3 32 5 36 7 1051 2 3 4 52 3 4 5 63 4 5 6 74 5 6 7 85 6 7 8 9
 

Sample Output
284680
 

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 0x3f3f3f3fstruct 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;}