1. 程式人生 > >LOJ #6010. 「網絡流 24 題」數字梯形

LOJ #6010. 「網絡流 24 題」數字梯形

整數 數字 attach inline ram column pla read const

#6010. 「網絡流 24 題」數字梯形

題目描述

給定一個由 n nn 行數字組成的數字梯形如下圖所示。梯形的第一行有 m mm 個數字。從梯形的頂部的 m mm 個數字開始,在每個數字處可以沿左下或右下方向移動,形成一條從梯形的頂至底的路徑。

分別遵守以下規則:

  1. 從梯形的頂至底的 m mm 條路徑互不相交;
  2. 從梯形的頂至底的 m mm 條路徑僅在數字結點處相交;
  3. 從梯形的頂至底的 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 201m,n20

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\n",-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 }

LOJ #6010. 「網絡流 24 題」數字梯形