#6010. 「网络流 24 题」数字梯形
题目描述
给定一个由 n nn 行数字组成的数字梯形如下图所示。梯形的第一行有 m mm 个数字。从梯形的顶部的 m mm 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径。
分别遵守以下规则:
- 从梯形的顶至底的 m mm 条路径互不相交;
- 从梯形的顶至底的 m mm 条路径仅在数字结点处相交;
- 从梯形的顶至底的 m mm 条路径允许在数字结点相交或边相交。
输入格式
第 1 11 行中有 2 22 个正整数 m mm 和 n nn,分别表示数字梯形的第一行有 m mm 个数字,共有 n nn 行。接下来的 n nn 行是数字梯形中各行的数字。
第 1 11 行有 m mm 个数字,第 2 22 行有 m+1 m + 1m+1 个数字 ……
输出格式
将按照规则 1,规则 2,和规则 3 计算出的最大数字总和并输出,每行一个最大总和。
样例
样例输入
2 5
2 3
3 4 5
9 10 9 1
1 1 10 1 1
1 1 10 12 1 1
样例输出
66
75
77
数据范围与提示
1≤m,n≤20 1 leq m, n leq 201≤m,n≤20
code
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 5 using namespace std; 6 const int N = 1010; 7 const int INF = 1e9; 8 9 struct Edge{ 10 int u,v,f,c,nxt; 11 Edge(){} 12 Edge(int a,int b,int flow,int cost,int nt) { 13 u = a;v = b;f = flow;c = cost;nxt = nt; 14 } 15 }e[100100]; 16 int head[N],dis[N],q[100100],pre[N],a[30][30],b[30][30]; 17 bool vis[N]; 18 int n,m,S,T,tn,L,R,Mc,ans,tot; 19 20 inline char nc() { 21 static char buf[100000],*p1 = buf,*p2 = buf; 22 return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2) ? EOF :*p1++; 23 } 24 inline int read() { 25 int x = 0,f = 1;char ch=nc(); 26 for (; ch<'0'||ch>'9'; ch=nc()) if(ch=='-')f=-1; 27 for (; ch>='0'&&ch<='9'; ch=nc()) x=x*10+ch-'0'; 28 return x*f; 29 } 30 void add_edge(int u,int v,int f,int c) { 31 e[++tot] = Edge(u,v,f,c,head[u]);head[u] = tot; 32 e[++tot] = Edge(v,u,0,-c,head[v]);head[v] = tot; 33 } 34 bool spfa() { 35 for (int i=1; i<=T; ++i) vis[i]=false,dis[i]=INF; 36 L = 1;R = 0; 37 dis[S] = 0; 38 q[++R] = S;vis[S] = true;pre[S] = 0; 39 while (L <= R) { 40 int u = q[L++]; 41 for (int i=head[u]; i; i=e[i].nxt) { 42 int v = e[i].v; 43 if (dis[v]>dis[u]+e[i].c && e[i].f > 0) { 44 dis[v] = dis[u] + e[i].c; 45 pre[v] = i; 46 if (!vis[v]) q[++R] = v,vis[v] = true; 47 } 48 } 49 vis[u] = false; 50 } 51 return dis[T]!=INF; 52 } 53 void mcf() { 54 int zf = INF; 55 for (int i=T; i!=S; i=e[pre[i]].u) 56 zf = min(zf,e[pre[i]].f); 57 for (int i=T; i!=S; i=e[pre[i]].u) 58 e[pre[i]].f -= zf,e[pre[i]^1].f += zf; 59 Mc += dis[T]*zf; 60 } 61 int work() { 62 Mc = 0; 63 while (spfa()) mcf(); 64 printf("%d ",-Mc); 65 } 66 void init() { 67 tot = 1; 68 memset(head,0,sizeof(head)); 69 } 70 void build_1() { 71 init(); 72 S = tn + tn + 1;T = tn + tn + 2; 73 for (int i=1; i<=n; ++i) 74 for (int j=1; j<=m+i-1; ++j) { 75 add_edge(b[i][j],b[i][j]+tn,1,-a[i][j]); 76 add_edge(b[i][j]+tn,b[i+1][j],1,0); 77 add_edge(b[i][j]+tn,b[i+1][j+1],1,0); 78 if (i==1) add_edge(S,b[i][j],1,0); 79 if (i==n) add_edge(b[i][j]+tn,T,1,0); 80 } 81 } 82 void build_2() { 83 init(); 84 S = tn + 1;T = tn + 2; 85 for (int i=1; i<=n; ++i) { 86 for (int j=1; j<=m+i-1; ++j) { 87 add_edge(b[i][j],b[i+1][j],1,-a[i][j]); 88 add_edge(b[i][j],b[i+1][j+1],1,-a[i][j]); 89 if (i==1) add_edge(S,b[i][j],1,0); 90 if (i==n) add_edge(b[i][j],T,INF,-a[i][j]); 91 } 92 } 93 } 94 void build_3() { 95 init(); 96 S = tn + 1;T = tn + 2; 97 for (int i=1; i<=n; ++i) { 98 for (int j=1; j<=m+i-1; ++j) { 99 add_edge(b[i][j],b[i+1][j],INF,-a[i][j]); 100 add_edge(b[i][j],b[i+1][j+1],INF,-a[i][j]); 101 if (i==1) add_edge(S,b[i][j],1,0); 102 if (i==n) add_edge(b[i][j],T,INF,-a[i][j]); 103 } 104 } 105 } 106 int main() { 107 m = read(),n = read(); 108 for (int i=1; i<=n; ++i) 109 for (int j=1; j<=m+i-1; ++j) a[i][j] = read(),b[i][j] = ++tn; 110 111 build_1();work(); 112 build_2();work(); 113 build_3();work(); 114 return 0; 115 }