洛谷 P2045 方格取数加强版【费用流】
题目链接:https://www.luogu.org/problemnew/show/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
题解:和昨天那题略像,就是限制点了,拆点再跑费用流。。。不写了,我上课去......
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 5010;//注意点数 5 const int M = N*8+10; 6 const int INF = 0x3f3f3f3f; 7 struct Edge { int to,next,cap,flow,cost; }edge[M]; 8 int head[N],tol; 9 int pre[N],dis[N]; 10 bool vis[N]; 11 int V; 12 void init(int n) { 13 V = n; 14 tol = 0; 15 memset(head,-1,sizeof(head)); 16 } 17 void addedge(int u,int v,int cap,int cost) { 18 edge[tol].to = v; edge[tol].cap = cap; edge[tol].cost = cost; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++; 19 edge[tol].to = u; edge[tol].cap = 0; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; 20 } 21 bool spfa(int s,int t) { 22 queue<int>q; 23 for(int i = 0;i < V;i++) { 24 dis[i] = INF; 25 vis[i] = false; 26 pre[i] = -1; 27 } 28 dis[s] = 0; 29 vis[s] = true; 30 q.push(s); 31 while(!q.empty()) { 32 int u = q.front(); 33 q.pop(); 34 vis[u] = false; 35 for(int i = head[u]; i != -1;i = edge[i].next) { 36 int v = edge[i].to; 37 if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost ) { 38 dis[v] = dis[u] + edge[i].cost; 39 pre[v] = i; 40 if(!vis[v]) { 41 vis[v] = true; 42 q.push(v); 43 } 44 } 45 } 46 } 47 if(pre[t] == -1) return false; 48 else return true; 49 } 50 int minCostMaxflow(int s,int t,int &cost) { 51 int flow = 0; 52 cost = 0; 53 while(spfa(s,t)) { 54 int Min = INF; 55 for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) { 56 if(Min > edge[i].cap - edge[i].flow) 57 Min = edge[i].cap - edge[i].flow; 58 } 59 for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) { 60 edge[i].flow += Min; 61 edge[i^1].flow -= Min; 62 cost += edge[i].cost * Min; 63 } 64 flow += Min; 65 } 66 return flow; 67 } 68 int main() { 69 int n, k, i, j, x, ans = 0; 70 scanf("%d%d", &n, &k); 71 init(n*n*2+3); 72 73 int s = n*n*2+1, t = n*n*2+2; 74 75 for(i = 1; i <= n; ++i) {//拆点限流 76 for(j = 1; j <= n; ++j) { 77 scanf("%d", &x); 78 addedge((i-1)*n+j, (i-1)*n+j + n*n, 1, -x);//存负权 79 if(k > 1) addedge((i-1)*n+j, (i-1)*n+j + n*n, k-1, 0);//注意判断 80 } 81 } 82 for(i = 1; i <= n ;++i) {//向右加边 83 for(j = 1; j < n; ++j) { 84 addedge((i-1)*n+j + n*n, (i-1)*n+j+1, k, 0); 85 } 86 } 87 for(i = 1; i < n; ++i) {//向下加边 88 for(j = 1; j <= n; ++j) { 89 addedge((i-1)*n+j + n*n, (i-1)*n+j+n, k, 0); 90 } 91 } 92 //源点、汇点 与 起点、终点连边 93 addedge(s, 1, k, 0); 94 addedge(n*n*2, t, k, 0); 95 96 minCostMaxflow(s, t, ans); 97 printf("%d\n", -ans); 98 return 0; 99 }