zoukankan      html  css  js  c++  java
  • hdu 2686 Matrix 最小费用最大流

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2686

    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. 
     
    题意描述:n*n的矩阵,每个数为正整数,要求从最左上的位置走到最右下的位置,每次只能向右或向下走一格,然后又从最右下的位置回到最左上的位置,每次只能向上或向左走一格,然后累加这两次路径上的数。注意每个格子只能走一次(除去最左上和最右下),即矩阵中的每个数只能加一次。
     
    算法分析:这道题可以运用DP来做,但我的DP思维有限,还不大熟悉,刚好最近刷图论题,介绍一下用最小费用最大流算法解之。
    把最左上看作源点,最右下看作汇点。从上往下走一次,再从下往上走一次,其实就等同于从上往下走两次罢了,即从源点到汇点找到两条价值最大且不相交的路径。
    首先拆点建图:(i-1)*n+j->(i-1)*n+j+n*n(w为1(注意:源点和汇点为2,因为要找到两条路),cost为矩阵中这个数值);
    (i-1)*n+j+n*n -> (i-1)*n+j+1(w为1,cost为0)
    (i-1)*n+j+n*n -> i*n+j(w为1,cost为0)
    然后用费用流求解即可。(不是题中明确说明每个数都为正吗,我dis[]函数初始化0WA了,这是为什么?)
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<cmath>
      6 #include<algorithm>
      7 #include<vector>
      8 #include<queue>
      9 #define inf 0x7fffffff
     10 using namespace std;
     11 const int maxn=20000+10;
     12 const int M = 9999999;
     13 
     14 int n,from,to;
     15 struct node
     16 {
     17     int v,flow,cost;
     18     int next;
     19 }edge[M*3];
     20 int head[maxn],edgenum;
     21 int dis[maxn],pre[maxn],pid[maxn],vis[maxn];
     22 int an[33][33];
     23 
     24 void add(int u,int v,int flow,int cost)
     25 {
     26     edge[edgenum].v=v ;edge[edgenum].flow=flow;
     27     edge[edgenum].cost=cost ;edge[edgenum].next=head[u];
     28     head[u]=edgenum++;
     29 
     30     edge[edgenum].v=u ;edge[edgenum].flow=0;
     31     edge[edgenum].cost=-cost ;edge[edgenum].next=head[v];
     32     head[v]=edgenum++;
     33 }
     34 
     35 int spfa()
     36 {
     37     memset(vis,0,sizeof(vis));
     38     memset(dis,-1,sizeof(dis));
     39     queue<int> Q;
     40     Q.push(from);
     41     dis[from]=0;
     42     vis[from]=1;
     43     while (!Q.empty())
     44     {
     45         int u=Q.front() ;Q.pop();
     46         vis[u]=0;
     47         for (int i=head[u] ;i!=-1 ;i=edge[i].next)
     48         {
     49             int v=edge[i].v;
     50             if (edge[i].flow>0 && dis[v]<dis[u]+edge[i].cost)
     51             {
     52                 dis[v]=dis[u]+edge[i].cost;
     53                 pre[v]=u;
     54                 pid[v]=i;
     55                 if (!vis[v])
     56                 {
     57                     vis[v]=1;
     58                     Q.push(v);
     59                 }
     60             }
     61         }
     62     }
     63     return dis[to];
     64 }
     65 
     66 int mincost()
     67 {
     68     int aug=0,maxflow=0;
     69     int ans=0;
     70     int ncase=0;
     71     while (1)
     72     {
     73         aug=inf;
     74         int tmp=spfa();
     75         if (tmp==0) break;
     76         for (int i=to ;i!=from ;i=pre[i])
     77         {
     78             if (edge[pid[i] ].flow<aug)
     79                 aug=edge[pid[i] ].flow;
     80         }
     81         for (int i=to ;i!=from ;i=pre[i])
     82         {
     83             edge[pid[i] ].flow -= aug;
     84             edge[pid[i]^1 ].flow += aug;
     85         }
     86         ans += tmp;
     87         ncase++;
     88         if (ncase==2) break;
     89     }
     90     return ans-an[1][1]-an[n][n];
     91 }
     92 
     93 int main()
     94 {
     95     while (scanf("%d",&n)!=EOF)
     96     {
     97         memset(head,-1,sizeof(head));
     98         edgenum=0;
     99         for (int i=1 ;i<=n ;i++)
    100         {
    101             for (int j=1 ;j<=n ;j++)
    102                 scanf("%d",&an[i][j]);
    103         }
    104         from=1;
    105         to=2*n*n;
    106         for (int i=1 ;i<=n ;i++)
    107         {
    108             for (int j=1 ;j<=n ;j++)
    109             {
    110                 int u=(i-1)*n+j;
    111                 int v=(i-1)*n+j+n*n;
    112                 add(u,v,1,an[i][j]);
    113                 if (j+1<=n) add(v,u+1,1,0);
    114                 if (i+1<=n) add(v,i*n+j,1,0);
    115             }
    116         }
    117         add(from,from+n*n,1,an[1][1]);
    118         add(n*n,to,1,an[n][n]);
    119         int sum=mincost();
    120         printf("%d
    ",sum);
    121     }
    122     return 0;
    123 }
  • 相关阅读:
    Java并发编程原理与实战二十九:Exchanger
    Java并发编程原理与实战二十八:信号量Semaphore
    Java并发编程原理与实战二十七:循环栅栏:CyclicBarrier
    Java并发编程原理与实战二十六:闭锁 CountDownLatch
    Java并发编程原理与实战二十五:ThreadLocal线程局部变量的使用和原理
    Java并发编程原理与实战二十四:简易数据库连接池
    Java并发编程原理与实战二十三:Condition原理分析
    Java并发编程原理与实战二十二:Condition的使用
    Java并发编程原理与实战二十一:线程通信wait&notify&join
    Java并发编程原理与实战二十:线程安全性问题简单总结
  • 原文地址:https://www.cnblogs.com/huangxf/p/4332014.html
Copyright © 2011-2022 走看看