洛谷 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 }
View Code

 

posted @ 2018-05-15 09:46  GraceSkyer  阅读(391)  评论(0编辑  收藏  举报

~~~~~~ACM大牛语录,激励一下~~~~~~

为了世界的和平,为了女生的安全,我拼命做题,做题,做题!

用最短的时间,刷最多的题!

给我一滴泪,我就看到了你全部的海洋!

seize the hour, seize the day.

人生难免有无奈,幸福走远了,或是感叹幸福来迟了.其实我一直相信,无论手中的幸福是多么微不足道的感觉,我会把握住那每一分,每一秒,当幸福依旧像那百鸟般飞逝,终究无法掌握时,我会感谢它,曾经降临过!

A自己的题,让别人郁闷去吧

WA肠中过,AC心中留 TLE耳边过,AC特别牛

天然的悲苦和伤逝,过去有过,以后还会有

^*^一步一步往上爬^*^

AC就像练级,比赛就像PK. 练级不如PK好玩

其实,世上本没有ACM,AC的人多了,也便有了!

AC无止尽~ Seek you forever~

找呀找呀找水题,找到一个AC一个呀!

AC是检验程序的唯一标准。

真的猛士,敢于直面惨淡的人生,敢于正视淋漓的鲜血……