poj3422 Kaka's Matrix Travels(最小费用最大流问题)

  1 /*
  2 poj3422 Kaka‘s Matrix Travels
  3 不知道 k次 dp做为什么不对???
  4 看了大牛的代码,才知道还可以这样做!
  5 开始没有理解将a 和 a‘ 之间建立怎样的两条边,导致程序一直陷入死循环,真心花了好长时间,快崩溃了。无语.....
  6 题意:有个方阵,每个格子里都有一个非负数,从左上角走到右下角,每次走一步,只能往右或往下走,经过的数字拿走
  7 每次都找可以拿到数字和最大的路径走,走k次,求最大和
  8
  9 这是 最大费用最大流 问题  每次spfa都找的是一条和最大的路径 s--到左上角的边流量是K限制增广次数
 10
 11 求最大费用最大流只需要把费用换成相反数,用最小费用最大流求解即可
 12
 13
 14 构图过程:
 15 每个点拆分成两个  a   a‘   之间建两条边(当然还要建退边),分别是   (费用为该点相反数,流量为1) (费用为0,流量为k-1)
 16 路过这点时,可以通过前边那条边拿到数字,
 17 以后再从这儿过,就没有数字可拿了,走的就是第二条边
 18
 19 然后是 没点向 右和下 建一条边  费用0,流量k
 20 */
 21 #include<iostream>
 22 #include<queue>
 23 #include<cstring>
 24 #include<cstdio>
 25 #define N 50000
 26 #define M 5005
 27 #define Max 0x3f3f3f3f
 28 using namespace std;
 29 class EDGE
 30 {
 31 public:
 32    int u, v, c, f;
 33    int next;
 34 };
 35 queue<int>q;
 36 EDGE edge[N];
 37 int cap[55][55], n, k;
 38 int pre[N], first[N];
 39 int dist[M], vis[M];
 40 int edgeN;
 41 int s, t;
 42 int maxFlow;
 43
 44 int spfa()
 45 {
 46     memset(dist, 0x3f, sizeof(dist));
 47     memset(vis, 0, sizeof(vis));
 48     memset(pre, -1, sizeof(pre));
 49     dist[s]=0;
 50     q.push(s);
 51     vis[s]=1;
 52     while(!q.empty())
 53     {
 54         int u=q.front();
 55         q.pop();
 56         vis[u]=0;
 57         for(int e=first[u]; e!=-1; e=edge[e].next)
 58         {
 59           int v=edge[e].v;
 60           if(dist[v]>dist[u] + edge[e].c && edge[e].f>0)
 61            {
 62                dist[v]=dist[u] + edge[e].c;
 63                pre[v]=e;
 64                if(!vis[v])
 65                {
 66                      vis[v]=1;
 67                      q.push(v);
 68            }
 69        }
 70     }
 71      }
 72      if(dist[t]==Max)
 73        return 0;
 74      return 1;
 75 }
 76
 77 void updateFlow()
 78 {
 79    int minF=Max;
 80    for(int e=pre[t]; e!=-1; e=pre[edge[e].u])
 81      if(minF>edge[e].f)
 82         minF=edge[e].f;
 83    for(int e=pre[t]; e!=-1; e=pre[edge[e].u])
 84    {
 85       edge[e].f-=minF;
 86       edge[e^1].f+=minF;
 87       maxFlow+=minF*edge[e].c;
 88    }
 89 }
 90
 91 void adde(int u, int v, int c, int f)
 92 {
 93     edge[edgeN].u=u; edge[edgeN].v=v;
 94     edge[edgeN].c=c; edge[edgeN].f=f;
 95     edge[edgeN].next=first[u]; first[u]=edgeN++;
 96
 97     edge[edgeN].u=v; edge[edgeN].v=u;
 98     edge[edgeN].c=-c; edge[edgeN].f=0;
 99     edge[edgeN].next=first[v]; first[v]=edgeN++;
100 }
101
102 int main()
103 {
104    int i, j;
105    while(scanf("%d%d", &n, &k)!=EOF)
106    {
107       maxFlow=0;
108       edgeN=0;
109       memset(first, -1, sizeof(first));
110       s=0; t=n*n*2+1;
111       for(i=1; i<=n; ++i)
112         for(j=1; j<=n; ++j)
113           scanf("%d", &cap[i][j]);
114       adde(s, 1, 0, k);
115       for(i=1; i<=n; ++i)
116         for(j=1; j<=n; ++j)//n*n个节点,拆点之后变成2*n*n个节点
117         {
118            int nb=(i-1)*n+j;
119            adde(2*nb-1, 2*nb, -cap[i][j], 1);//注意:a到a`是建立两条边,但是两条边的费用和容量不一样
120            adde(2*nb-1, 2*nb, 0, k-1);
121            if(j<n)//向右建图
122              adde(2*nb, 2*(nb+1)-1, 0, k);
123            if(i<n)//向下建图
124              adde(2*nb, 2*(nb+n)-1, 0, k);
125     }
126        adde(n*n*2, t, 0, k);
127
128        while(spfa())//建好图之后,直接调用最小费用最大流模板就好了
129           updateFlow();
130        printf("%d\n", -maxFlow);
131    }
132    return 0;
133 }

poj3422 Kaka's Matrix Travels(最小费用最大流问题)

时间: 2024-10-07 12:16:13

poj3422 Kaka's Matrix Travels(最小费用最大流问题)的相关文章

POj3422 Kaka&#39;s Matrix Travels 最小费用最大流 拆点

题目链接: poj3422 题意: 有一个N X N的矩阵, 矩阵的每一小格都有且仅有一个数字v,kaka每经过一个数字就会把它捡起来并将那个数字加到sum上去. 现在kaka能通过向下或向右走的方式从 (1,1)到(n,n)  K次,问kaka能取到的最大的sum是多少. 解题思路: 题目问题可以抽象为   求多次可走重复路的最长路的最大和问题 首先想到的就应该是最小费用最大流, 而题目要求的最大和值,那么应求就是最大费用最大流, 仅仅只需要将代码中的最小路算法改为最长路算法即可 题目的条件是

POJ3422 Kaka&#39;s Matrix Travels(最大费用最大流 + 拆点)

题目链接:http://poj.org/problem?id=3422 题意:有一个n*n的矩阵,格子中的元素是费用,KaKa从左上角开始出发要到达右下角,但是他只能向下走或者向右走,且走过的格子赋值为0,可以走K次,问K次后KaKa能获得的最大费用是多少? 思路:首先解释一下为什么要拆点?    因为要获得最大费用,所以假设当前步选择先下走,最终得到的结果可能不是最大值,但根据题意却把走过的格子赋为0了,这就影响了最终结果.所以进行拆点,把每个点拆成两个点,入度点和出度点,本点的入度点连接着本

POJ3422 Kaka&#39;s Matrix Travels[费用流]

Kaka's Matrix Travels Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9522   Accepted: 3875 Description On an N × N chessboard with a non-negative number in each grid, Kaka starts his matrix travels with SUM = 0. For each travel, Kaka mo

POJ3422 Kaka&#39;s Matrix Travels 【最大费用最大流】

Kaka's Matrix Travels Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8006   Accepted: 3204 Description On an N × N chessboard with a non-negative number in each grid, Kaka starts his matrix travels with SUM = 0. For each travel, Kaka mo

POJ 3422 Kaka&#39;s Matrix Travels(费用流)

POJ 3422 Kaka's Matrix Travels 题目链接 题意:一个矩阵,从左上角往右下角走k趟,每次走过数字就变成0,并且获得这个数字,要求走完之后,所获得数字之和最大 思路:有点类似区间k覆盖的建图方法,把点拆了,每个点有值的只能选一次,其他都是无值的,利用费用流,入点出点之间连一条容量1,有费用的边,和一条容量k - 1,费用0的边,然后其他就每个点和右边和下边2个点连边,然后跑费用流 代码: #include <cstdio> #include <cstring&g

poj 3422 Kaka&#39;s Matrix Travels (费用流)

Kaka's Matrix Travels Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7743   Accepted: 3111 Description On an N × N chessboard with a non-negative number in each grid, Kaka starts his matrix travels with SUM = 0. For each travel, Kaka mo

POJ 3422 Kaka&#39;s Matrix Travels 【最小费用最大流】

题意: 卡卡有一个矩阵,从左上角走到右下角,卡卡每次只能向右或者向下.矩阵里边都是不超过1000的正整数,卡卡走过的元素会变成0,问卡卡可以走k次,问卡卡最多能积累多少和. 思路: 最小费用最大流的题目. 建图自己没想出来,看了大神的建边,把每个点分解成两个点,一个代表进入一个代表出去,然后每个进入和每个出去连边,容量是1价值是这个点的矩阵的数值.然后因为可以不进去,所以起点要和别的矩阵元素的起点建边,终点也要和别的矩阵矩阵元素的起点建边,最后跑下最小费用最大流. 这题最右下角的矩阵元素需要特殊

POJ 3422 Kaka&#39;s Matrix Travels (最小费用最大流)

POJ 3422 Kaka's Matrix Travels 链接:http://poj.org/problem?id=3422 题意:有一个N*N的方格,每个方格里面有一个数字.现在卡卡要从左上角走到右下角,规定每次只能向下或者向右走,每次走到一个格子,将得到该格子的数字,并且该格子的数字变为0.当卡卡走一次时,很容易求出最大值,问卡卡走k次,能够得到的最大值为多少. 思路:最小费用最大流 关键是如何构图 1. 将N*N个格点拆分为两个点(i,i + N*N),每个点之间连一条流量为1,费用为

POJ 3422 Kaka&#39;s Matrix Travels(最大费用最大流 + 拆点)

题目链接:http://poj.org/problem?id=3422 Description On an N × N chessboard with a non-negative number in each grid, Kaka starts his matrix travels with SUM = 0. For each travel, Kaka moves one rook from the left-upper grid to the right-bottom one, taking