HDU 3376 费用流 Matrix Again

咳咳,内个,内什么,白书上的费用流模板没过,后来换了种存图方式才过。

题意:

给出一个n × n的矩阵,每个格子中有一个数字代表权值,找出从左上角出发到右下角的两条不相交的路径(起点和终点除外),使得两条路径权值之和最大。

分析:

如果n比较小的话是可以DP的,但是现在n非常大,DP会超时的。

这个用费用流来求解:

因为每个点只能走一次,所以先拆点,两点之间连一条容量为1费用为对应格子权值的边,如果是起点或终点,因为要走两次,所以要连容量为2的边。

对于不同格子之间,如果能到达,连一条容量为INF,费用为0的边。

因为算法求的是最小费用,所以我们把每个格子的相反数当做费用去连边,最后再取相反数。

因为起点和终点容量为2,计算出来的最大权值重复计算了左上角和右下角的权值,所以答案应该再减去这两个数。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <vector>
  6 #include <queue>
  7 using namespace std;
  8
  9 const int maxn = 600;
 10 const int maxnode = maxn * maxn * 2;
 11 const int maxm = 1000000 + 10;
 12 const int INF = 0x3f3f3f3f;
 13
 14 struct Edge
 15 {
 16     int from, to, cap, flow, cost;
 17     int nxt;
 18     Edge() {}
 19     Edge(int u, int v, int cap, int f, int cost, int nxt):from(u), to(v), cap(cap), flow(f), cost(cost), nxt(nxt) {}
 20 };
 21
 22 int ecnt;
 23 Edge edges[maxm << 2];
 24 int head[maxnode];
 25
 26 void AddEdge(int u, int v, int cap, int cost)
 27 {
 28     edges[ecnt] = Edge(u, v, cap, 0, cost, head[u]);
 29     head[u] = ecnt++;
 30     edges[ecnt] = Edge(v, u, 0, 0, -cost, head[v]);
 31     head[v] = ecnt++;
 32 }
 33
 34 int row;
 35 int A[maxn][maxn];
 36
 37 int n;
 38 int d[maxnode + 10], p[maxnode + 10], a[maxnode + 10];
 39 bool inq[maxnode + 10];
 40
 41 bool SPFA(int s, int t)
 42 {
 43     memset(inq, false, sizeof(inq));
 44     memset(p, -1, sizeof(p));
 45     memset(d, 0x3f, sizeof(d));
 46     inq[s] = true;
 47     d[s] = 0;
 48     a[s] = INF;
 49
 50     queue<int> Q;
 51     Q.push(s);
 52     while(!Q.empty())
 53     {
 54         int u = Q.front(); Q.pop(); inq[u] = false;
 55         for(int i = head[u]; ~i; i = edges[i].nxt)
 56         {
 57             Edge& e = edges[i];
 58             int v = e.to;
 59             if(e.flow < e.cap && d[u] + e.cost < d[v])
 60             {
 61                 d[v] = d[u] + e.cost;
 62                 p[v] = i;
 63                 a[v] = min(a[u], e.cap - e.flow);
 64                 if(!inq[v]) { inq[v] = true; Q.push(v); }
 65             }
 66         }
 67     }
 68
 69     return d[t] != INF;
 70 }
 71
 72 int Mincost(int s, int t)
 73 {
 74     int flow = 0;
 75     int cost = 0;
 76     while(SPFA(s, t))
 77     {
 78         flow += a[t];
 79         cost += d[t] * a[t];
 80         int u = t;
 81         while(u != s)
 82         {
 83             edges[p[u]].flow += a[t];
 84             edges[p[u]^1].flow -= a[t];
 85             u = edges[p[u]].from;
 86         }
 87     }
 88     return cost;
 89 }
 90
 91 int main()
 92 {
 93     while(scanf("%d", &row) == 1)
 94     {
 95         for(int i = 0; i < row; i++)
 96             for(int j = 0; j < row; j++) scanf("%d", &A[i][j]);
 97
 98         n = row * row;
 99         int s = 0, t = n * 2 - 1;
100         ecnt = 0;
101         memset(head, -1, sizeof(head));
102
103         //build graph
104         for(int i = 0; i < row; i++)
105             for(int j = 0; j < row; j++)
106             {
107                 int u = i * row + j;
108                 int v = u + n;
109                 int cap = 1;
110                 if(u == 0 || u == n - 1) cap++;
111                 AddEdge(u, v, cap, -A[i][j]);
112
113                 int w;
114                 if(i < row - 1)
115                 {
116                     w = u + row;
117                     AddEdge(v, w, INF, 0);
118                 }
119                 if(j < row - 1)
120                 {
121                     w = u + 1;
122                     AddEdge(v, w, INF, 0);
123                 }
124             }
125
126         n <<= 1;
127         printf("%d\n", -Mincost(s, t) - A[0][0] - A[row-1][row-1]);
128     }
129
130     return 0;
131 }

代码君

时间: 2024-10-15 11:27:06

HDU 3376 费用流 Matrix Again的相关文章

POJ 3422 HDU 2686,3376 费用流拆点建图

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3376 http://acm.hdu.edu.cn/showproblem.php?pid=2686 http://poj.org/problem?id=3422 POJ 3422为从矩阵左上角走到右下角,最多走k次,每个格子里的数字只能算一次,后面可以重复经过,求经过的各个数字的和的最大值. 拆点,入点向出点连流量为1,费用为当前格子负值的边,向下方,右方连边,流量为k,费用为0,起点连流量为1,

hdu 2686 费用流 / 双线程DP

题意:给一个方阵,求从左上角出到右下角(并返回到起点),经过每个点一次不重复,求最大获益(走到某处获得改点数值),下来时每次只能向右或向下,反之向上或向左. 俩种解法: 1  费用流法:思路转化:从左上角流出2的流量,(表示走俩条路),归于右下角,可以走就有边(右和下),权为负的费用,源点连起点,汇点连终点,流量为2. 除源汇外所有点一分为2,Y向X对应点有流量1的边,之前边为X到Y的(原图),这样处理解决每个点只最多走一次(除了源汇外)(X部只出,Y部要出必先回到X对应点).跑最小费用最大流即

Going Home HDU - 1533 (费用流)

Going Home HDU - 1533 1 //费用流初探 2 #include <iostream> 3 #include <queue> 4 #include <cstring> 5 #include <cstdio> 6 #include <algorithm> 7 using namespace std; 8 const int inf = 0x3f3f3f3f; 9 const int maxn = 110; 10 char gra

hdu 5045 费用流

滚动建图,最大费用流(每次只有就10个点的二分图).复杂度,m/n*(n^2)(n<=10),今年网络赛唯一网络流题,被队友状压DP秒了....难道网络流要逐渐退出历史舞台???.... #include<iostream> //78ms #include<cstdio> #include<queue> using namespace std; const double inf =0x3f3f3f3f; const int maxv=50,maxe=500; in

hdu 4406 费用流

这题问题就是当前时刻到底选择哪门课程,易知选择是和分数有关的,并且是一个变化的权值,所以可以用拆点的方式,把从基础分到100分都拆成点,但若这样拆点的话,跑费用流时就必须保证顺序,这样就麻烦了..观察公式,发现同一门课,分数越高,权值是越低的,所以这是一个单调的,这样的话就可以对每一个分数建一条边,费用流会一条一条的跑. 注意将课程放在X集 #include<cstdio> #include<queue> #include<algorithm> #include<

HDU 5045 费用流求最大权

点击打开链接 题意:有n个人和m到题目,每个人做对的概率以矩阵形式给出,问如何分配才可以使做对的概率最大,有一个限制条件是做到目前为止每两个人的做题数量差距不能超过1,也就是前n道题目,必须一人做一个 思路:网上都是dp多一点,用网络流也可以,不过麻烦很多,可是本弱是一点dp都不会的选手啊,只能用网络流了,对于那个限制条件,我们可以以前n道题建一次图,然后再来n个,不过就直接建完就可以了,然后我们要求的是什么呢,很明显是最大权,而最大费用最大流刚好可以解决,这里面的费用流有两种方法,用spfa找

HDU 3667 费用流 拆边 Transportation

题意: 有N个城市,M条有向道路,要从1号城市运送K个货物到N号城市. 每条有向道路<u, v>运送费用和运送量的平方成正比,系数为ai 而且每条路最多运送Ci个货物,求最小费用. 分析: 拆边,每条边拆成费用为a, 3a, 5a的边,这样就能保证每条边的费用和流量的平方成正比. 因为最多运送K个货物,所以增加一个源点和城市1连一条容量为K费用为0的边. 跑一边最小费用最大流,如果满流才有解. 1 #include <iostream> 2 #include <cstdio&

HDU 5644 (费用流)

Problem King's Pilots (HDU 5644) 题目大意 举办一次持续n天的飞行表演,第i天需要Pi个飞行员.共有m种休假计划,每个飞行员表演1次后,需要休假Si天,并提供Ti报酬来进行下一次表演.刚开始拥有k个飞行员.也可以招募飞行员来进行表演(数量无限),需要提供报酬q,在p天后参加表演.询问使表演顺利进行的最少花费,若无法进行,输出No solution. 解题分析 搬运官方题解: 稍微解释一下: 首先忽略Xi.Yi向T的流量表示第i天有多少人参加表演(第2条).S向Y1

HDU 3667 费用流(拆边)

题意:有n个城市(1~n),m条有向边:有k件货物要从1运到n,每条边最多能运c件货物,每条边有一个危险系数ai,经过这条路的费用需要ai*x2(x为货物的数量),问所有货物安全到达的费用. 思路:c<=5,这里可以做文章:把每条边拆成c条边,容量都为1,费用为ai*(2*i-1)(第二个i是指拆边时的第几条边).推导:x2-(x-1)2=2x-1. 代码: 1 #include<stdio.h> 2 #include<string.h> 3 #define min(x,y)