洛谷P4013 数字梯形问题(费用流)
2018-07-23 05:31:04来源:博客园 阅读 ()
题意
$N$行的矩阵,第一行有$M$个元素,第$i$行有$M + i - 1$个元素
问在三个规则下怎么取使得权值最大
Sol
我只会第一问qwq。。
因为有数量的限制,考虑拆点建图,把每个点拆为$a_1$和$b_1$,两点之间连流量为$1$,费用为权值的边
从$b_i$向下方和右下的$a_1$连一条流量为$1$,费用为$0$边
从$S$向第一层的$a_1$连流量为$1$,费用为$0$的边,从$b_N$到$T$连流量为$1$,费用为$0$的边
对于第二问,因为没有点的个数的限制,那么就不用拆点了,直接向能到达的点连流量为$1$,费用为点权的边
对于第三问,直接把第二问中的所有边为流量设为$INF$(除了从$S$出发的)
#include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; const int MAXN = 1e5 + 10, INF = 1e9 + 10; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') {if(c == '-') f = 1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } int N, M, S = 0, T = 1e5 + 1; int a[21][21]; struct Edge { int u, v, w, f, nxt; }E[MAXN]; int head[MAXN << 1], num = 0; inline void add_edge(int x, int y, int w, int f) { E[num] = (Edge){x, y, w, f, head[x]}; head[x] = num++; } inline void AddEdge(int x, int y, int w, int f) { add_edge(x, y, w, f); add_edge(y, x, -w, 0); } int anscost, dis[MAXN], vis[MAXN], Pre[MAXN]; bool SPFA() { memset(dis, -0x3f, sizeof(dis)); memset(vis, 0, sizeof(vis)); queue<int> q; q.push(S); dis[S] = 0; while(!q.empty()) { int p = q.front(); q.pop(); vis[p] = 0; for(int i = head[p]; i !=- 1; i = E[i].nxt) { int to = E[i].v; if((dis[to] < dis[p] + E[i].w) && E[i].f > 0) { dis[to] = dis[p] + E[i].w; Pre[to] = i; if(!vis[to]) q.push(to), vis[to] = 1; } } } return dis[T] > 0; } int F() { int nowflow = INF; for(int i = T; i != S; i = E[Pre[i]].u) nowflow = min(nowflow, E[Pre[i]].f); for(int i = T; i != S; i = E[Pre[i]].u) E[Pre[i]].f -= nowflow, E[Pre[i] ^ 1].f += nowflow; anscost += dis[T] * nowflow; } int MCMF() { anscost = 0; while(SPFA()) F(); return anscost; } int be[21][21], tot = 0, X; void Solve1() { memset(head, -1, sizeof(head)); num = 0; for(int i = 1; i < N; i++) { for(int j = 1; j <= M + i - 1; j++) { AddEdge(be[i][j], be[i][j] + X, a[i][j], 1); AddEdge(be[i][j] + X, be[i + 1][j], 0, 1); AddEdge(be[i][j] + X, be[i + 1][j + 1], 0, 1); } } for(int i = 1; i <= M; i++) AddEdge(S, be[1][i], 0, 1); for(int i = 1; i <= N + M - 1; i++) AddEdge(be[N][i], be[N][i] + X, a[N][i], 1), AddEdge(be[N][i] + X, T, 0, 1); printf("%d\n", MCMF()); } void Solve2() { memset(head, -1, sizeof(head)); num = 0; for(int i = 1; i < N; i++) { for(int j = 1; j <= M + i - 1; j++) { AddEdge(be[i][j], be[i + 1][j + 1], a[i][j], 1); AddEdge(be[i][j], be[i + 1][j], a[i][j], 1); } } for(int i = 1; i <= M; i++) AddEdge(S, be[1][i], 0, 1); for(int i = 1; i <= N + M - 1; i++) AddEdge(be[N][i], T, a[N][i], INF); printf("%d\n", MCMF()); } void Solve3() { memset(head, -1, sizeof(head)); num = 0; for(int i = 1; i < N; i++) for(int j = 1; j <= M + i - 1; j++) { AddEdge(be[i][j], be[i + 1][j + 1], a[i][j], INF); AddEdge(be[i][j], be[i + 1][j], a[i][j], INF); } for(int i = 1; i <= M; i++) AddEdge(S, be[1][i], 0, 1); for(int i = 1; i <= N + M - 1; i++) AddEdge(be[N][i], T, a[N][i], INF); printf("%d\n", MCMF()); } int main() { memset(head, -1, sizeof(head)); M = read(); N = read(); X = (N + M - 1) * N; for(int i = 1; i <= N; i++) for(int j = 1; j <= M + i - 1; j++) a[i][j] = read(), be[i][j] = ++tot; Solve1(); Solve2(); Solve3(); return 0; } /* */
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
上一篇:秋招复习-C++( 一)
下一篇:GCD LCM 素数 快速幂
- 洛谷P1164->小A点菜 2020-05-18
- 括号生成 2020-04-09
- 洛谷P1907口算练习题 2020-03-24
- L1-007 念数字 (10分) 2020-03-22
- Qt5小Demo之猜数字游戏 2020-03-19
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash