您的位置:首页 > 其它

JZOJ 3447【NOIP2013模拟联考2】摘取作物

2017-05-31 20:57 483 查看

Description:

Feather的农场里有N*M块地,排列成N行,每行M块地。Feather在每块地里种植了不同的农作物。现在这些农作物都成熟了,可以摘取下来出售了。其中第i行第j列的地里的农作物的价值为W[i,j]。

JackRabbit是Feather的好友,平时经常为Feather的农作物除草除虫。为了答谢JackRabbit,Feather决定把一部分农作物送给JackRabbit。JackRabbit很高兴,恨不得一下子把农场里的农作物摘空。

为了防止JackRabbit把农作物摘空,Feather提出了两个条件:

1.每行最多选取两块地;

2.每列最多选取两块地。

这下子把JackRabbit难住了。如何在满足这两个条件的前提下,使得摘取的农作物的价值之和最大呢?

Input:

第一行是两个整数N和M(3≤N≤30,3≤M≤30)。

以下N行每行M个整数,表示每块地的农作物的价值W[i,j](0≤W[i,j]≤10000)。

Output:

输出一个数,表示在满足条件的前提下摘取的农作物的价值之和的最大值。

Sample Input:

3 3

1 5 3

4 7 5

0 4 1

Sample Output:

21

【样例说明】

第一行选5和3,第二行选4和5,第三行选0和4,总和为21,是满足条件的最佳选取方案。

Data Constraint

40% n,m<=10

100% n,m<=30

题目大意:

给一个n*m的矩阵,每一行、每一列只能选两个数,求选出的数的和最大是多少。

题解:

当时我正在做其它题,前面的ifleaking转过来说:“不会网络流,随便来一题都不会”。

我一看,这不是费用流吗?于是开森地打了个最大费用最大流,WA50。

这个方法:

x坐标做一群点,源点到它们连流量为2,费用为0的弧.

y坐标做一群点,它们到汇点连流量为2费用为0的弧。

x到y连流量为1,费用为对应的作物值。

哦。原来是可行流啊。

zkw费用流怎么改可行流啊?上zkw博客,什么鬼,看不懂。

某LL说用SPFA就好了,于是看了一波题解,虽然不会证,好像挺有道理。

SPFA详见这里

但zkw怎么改啊?啊?啊?

某Wyt说,你建一些两排两列空点不就好了吗?

哇,肿么就辣么机智呢?

Code:

#include<cstdio>
#include<cstring>
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;

const int INF = 1 << 30, M = 10000;

int n, m, a[35][35];
int final[80], tot = 1;
struct node {
int to, next, r, w;
}e[5000];
int S, T, bz[80], dis[80];
int ans1, ans2;

void link(int x, int y, int r, int w) {
e[++ tot].next = final[x], e[tot].to = y, e[tot].r = r, e[tot].w = w, final[x] = tot;
e[++ tot].next = final[y], e[tot].to = x, e[tot].r = 0, e[tot].w = -w, final[y] = tot;
}
void Init() {
scanf("%d %d", &n, &m);
fo(i, 1, n) fo(j, 1, m)
scanf("%d", &a[i][j]);
n += 2; m += 2;
fo(i, 1, n) fo(j, 1, m) link(i, j + n, 1, M - a[i][j]);
S = n + m + 1, T = S + 1;
fo(i, 1, n) link(S, i, 2, 0);
fo(i, 1, m) link(i + n, T, 2, 0);
link(T, S, INF, -INF);
}

int aug(int x, int flow) {
if(x == T) {
ans1 += flow;
ans2 += dis[S] * flow;
return flow;
}
bz[x] = 1;
int use = 0;
for(int i = final[x]; i; i = e[i].next)
if(!bz[e[i].to] && e[i].r && dis[x] == dis[e[i].to] + e[i].w) {
int tmp = aug(e[i].to, min(flow - use, e[i].r));
e[i].r -= tmp; e[i ^ 1].r += tmp; use += tmp;
if(use == flow) return use;
}
return use;
}

bool change() {
int minh = INF;
fo(i, 1, T) if(bz[i])
for(int k = final[i]; k; k = e[k].next) if(e[k].r && !bz[e[k].to])
minh = min(minh, dis[e[k].to] + e[k].w - dis[i]);
if(minh == INF) return 0;
fo(i, 1, T) if(bz[i])
dis[i] += minh;
return 1;
}

int main() {
freopen("pick.in", "r", stdin);
freopen("pick.out", "w", stdout);
Init();
do do memset(bz, 0, sizeof(bz));
while(aug(S, INF));
while(change());
printf("%d", ans1 * M - ans2);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: