洛谷 P2045 方格取数加强版
题目描述
给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大
输入格式
第一行两个数n,k(1<=n<=50, 0<=k<=10)
接下来n行,每行n个数,分别表示矩阵的每个格子的数
输出格式
一个数,为最大和
输入输出样例
输入 #1
3 1 1 2 3 0 2 1 1 4 2
输出 #1
11
说明/提示
每个格子中的数不超过1000
思路:一道比较好的费用流题目。道理还是比较容易想的,但是我还是想了很长时间。。。
我个人的做法是这样的,对于一个格子,我们把它拆成4个点,分成:一个入点,一个出点,和两个中间点,入点到一个中间点连一条容量为1,边权为当前格子权值的边,到另一个中间点连一条容量为K-1,边权为0的边,两个中间点再向出点连各自的边,容量分别为1和K-1(均为inf也可以),边权均为0;
对于每一个出点,向右方向和下方向的格子的入点连容量为K,边权为0的边。最后源点和汇点分别向(1,1)(n,n)连边。
PS:我的做法其实过于麻烦,事实上只要拆成2个点即可。无需在拆中间点。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 const int N = 2e4 + 5; 8 const int M = 1e5 + 5; 9 struct edge{ 10 int from, to, cap, dis; 11 }e[M << 1]; 12 int head[N], nxt[M << 1], tot = 1; 13 void adde(int f, int t, int c, int d) 14 { 15 e[++ tot] = (edge){f, t, c, d}; 16 nxt[tot] = head[f]; 17 head[f] = tot; 18 } 19 int n, st, ed; 20 const int inf = 0x3f3f3f3f; 21 int dist[N], inq[N], pre[N]; 22 queue <int> Q; 23 bool spfa() 24 { 25 memset(dist, 0x3f, sizeof dist); 26 memset(inq, 0, sizeof inq); 27 memset(pre, 0, sizeof pre); 28 while(!Q.empty()) Q.pop(); 29 dist[st] = 0; 30 inq[st] = 1; 31 Q.push(st); 32 while(!Q.empty()) 33 { 34 int u = Q.front(); 35 Q.pop(); 36 inq[u] = 0; 37 for(int i = head[u]; i; i = nxt[i]) 38 { 39 int v = e[i].to; 40 if(dist[v] > dist[u] + e[i].dis && e[i].cap) 41 { 42 dist[v] = dist[u] + e[i].dis; 43 pre[v] = i; 44 if(!inq[v]) 45 { 46 inq[v] = 1; 47 Q.push(v); 48 } 49 } 50 } 51 } 52 return (dist[ed] != inf); 53 } 54 int cost = 0; 55 void redate() 56 { 57 int fl = inf; 58 for(int i = pre[ed]; i; i = pre[e[i].from]) fl = min(fl, e[i].cap); 59 for(int i = pre[ed]; i; i = pre[e[i].from]) 60 { 61 e[i].cap -= fl; 62 e[i^1].cap += fl; 63 cost += fl * e[i].dis; 64 } 65 } 66 void mcmf() 67 { 68 while(spfa()) redate(); 69 } 70 int K; 71 int num[N]; 72 void solve() 73 { 74 st = 0, ed = 5*n*n; 75 adde(st, 1, K, 0); 76 adde(1, st, 0, 0); 77 adde(4*n*n, ed, K, 0); 78 adde(ed, 4*n*n, 0, 0); 79 for(int i = 1; i <= n*n; i ++) 80 { 81 adde(i, i + n*n, 1, -num[i]); 82 adde(i + n*n, i, 0, num[i]);//(1,2 83 adde(i, i + 2*n*n, K - 1, 0); 84 adde(i + 2*n*n, i, 0, 0);//(1,3 85 adde(i + n*n, i + 3*n*n, 1, 0); 86 adde(i + 3*n*n, i + n*n, 0, 0);//(2,4 87 adde(i + 2*n*n, i + 3*n*n, K - 1, 0); 88 adde(i + 3*n*n, i + 2*n*n, 0, 0);//(3,4 89 } 90 for(int i = 1; i <= n*n; i ++) 91 { 92 if(i % n) 93 { 94 adde(i + 3*n*n, i + 1, K, 0); 95 adde(i + 1, i + 3*n*n, 0, 0); 96 } 97 if(i <= n*(n - 1)) 98 { 99 adde(i + 3*n*n, i + n, K, 0); 100 adde(i + n, i + 3*n*n, 0, 0); 101 } 102 } 103 } 104 int main() 105 { 106 scanf("%d%d", &n, &K); 107 for(int i = 1; i <= n; i ++) 108 for(int j = 1; j <= n; j ++) 109 scanf("%d", &num[j + (i - 1)*n]); 110 solve(); 111 mcmf(); 112 printf("%d\n", -cost); 113 return 0; 114 }