【wikioi】1033 蚯蚓的游戏问题(费用流)
http://wikioi.com/problem/1033/
这题也是很水的费用流啊,同之前那题一样,拆点然后建边,容量为1,费用为点权。然后建个源连第一行每个点,容量为1,费用为0,然后最后一行每个点连汇,容量为1,费用为0。
最后再建个超级源连一条边到源,容量为k,费用为0。再建个超级汇,汇连边到它,容量为k,费用为0。
跑一次费用流即可。
#include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> using namespace std; #define rep(i, n) for(int i=0; i<(n); ++i) #define for1(i,a,n) for(int i=(a);i<=(n);++i) #define for2(i,a,n) for(int i=(a);i<(n);++i) #define for3(i,a,n) for(int i=(a);i>=(n);--i) #define for4(i,a,n) for(int i=(a);i>(n);--i) #define CC(i,a) memset(i,a,sizeof(i)) #define read(a) a=getint() #define print(a) printf("%d", a) #define dbg(x) cout << #x << " = " << x << endl #define printarr(a, n, m) rep(aaa, n) { rep(bbb, m) cout << a[aaa][bbb]; cout << endl; } inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; } inline const int max(const int &a, const int &b) { return a>b?a:b; } inline const int min(const int &a, const int &b) { return a<b?a:b; } const int N=5500, M=1000000, oo=~0u>>1; int ihead[N], cnt=1, d[N], p[N], n, m, k, vis[N], q[N], front, tail, id[35][70]; struct ED { int from, to, cap, w, next; } e[M]; inline void add(const int &u, const int &v, const int &c, const int &w) { e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v; e[cnt].from=u; e[cnt].cap=c; e[cnt].w=w; e[++cnt].next=ihead[v]; ihead[v]=cnt; e[cnt].to=u; e[cnt].from=v; e[cnt].cap=0; e[cnt].w=-w; } inline const bool spfa(const int &s, const int &t) { for1(i, 0, t) d[i]=1000000000, vis[i]=0; vis[s]=1; d[s]=front=tail=0; q[tail++]=s; int u, v, i; while(front!=tail) { u=q[front++]; if(front==N) front=0; for(i=ihead[u]; i; i=e[i].next) if(e[i].cap && d[v=e[i].to]>d[u]+e[i].w) { d[v]=d[u]+e[i].w; p[v]=i; if(!vis[v]) { vis[v]=1, q[tail++]=v; if(tail==N) tail=0; } } vis[u]=0; } return d[t]!=1000000000; } int mcf(const int &s, const int &t) { int ret=0, f, u; while(spfa(s, t)) { for(f=oo, u=t; u!=s; u=e[p[u]].from) f=min(f, e[p[u]].cap); for(u=t; u!=s; u=e[p[u]].from) e[p[u]].cap-=f, e[p[u]^1].cap+=f; ret+=d[t]*f; } return ret; } int main() { read(n); read(m); read(k); int s=0, t=5200, c, now, tot=0, pw=(n+m)*n; for1(i, 1, n) for1(j, 1, m+i-1) id[i][j]=++tot; for1(i, 1, n) for1(j, 1, m+i-1) { read(c); now=id[i][j]; add(now, now+pw, 1, -c); if(i<n) add(now+pw, id[i+1][j], 1, 0), add(now+pw, id[i+1][j+1], 1, 0); } for1(j, 1, m) add(s, id[1][j], 1, 0); for1(j, 1, m+n-1) add(id[n][j]+pw, t, 1, 0); add(t+1, s, k, 0); add(t, t+2, k, 0); printf("%d\n", -mcf(t+1, t+2)); return 0; }
题目描述 Description
在一块梯形田地上,一群蚯蚓在做收集食物游戏。蚯蚓们把梯形田地上的食物堆积整理如下:
a(1,1) a(1,2)…a(1,m)
a(2,1) a(2,2) a(2,3)…a(2,m) a(2,m+1)
a(3,1) a (3,2) a(3,3)…a(3,m+1) a(3,m+2)
……
a(n,1) a(n,2) a(n,3)… a(n,m+n-1)
它们把食物分成n行,第1行有m堆的食物,每堆的食物量分别是a(1,1),a(1,2),…,a(1,m);
第2行有m+1堆食物,每堆的食物量分别是a(2,1),a(2,2),…, a(2,m+1);以下依次有m+2堆、m+3堆、…m+n-1堆食物。
现在蚯蚓们选择了k条蚯蚓来测试它们的合作能力(1≤ k ≤m)。测试法如下:第1条蚯蚓从第1行选择一堆食物,然后往左下或右下爬,并收集1堆食物,例如从a(1,2)只能爬向a(2,2) 或a(2,3),而不能爬向其它地方。接下来再爬向下一行收集一堆食物,直到第n行收集一堆食物。第1条蚯蚓所收集到的食物量是它在每一行所收集的食物量 之和;第2条蚯蚓也从第1行爬到第n行,每行收集一堆食物,爬的方法与第1条蚯蚓相类似,但不能碰到第1条蚯蚓所爬的轨迹;一般地,第i 条蚯蚓从第1行爬到第 n行,每行收集一堆食物,爬的方法与第1条蚯蚓类似,但不能碰到前 I-1 条蚯蚓所爬的轨迹。这k条蚯蚓应该如何合作,才能使它们所收集到的食物总量最多?收集到的食物总量可代表这k条蚯蚓的合作水平。
- Ø编程任务:
给定上述梯形m、n和k的值(1≤k≤m≤30;1≤n≤30)以及梯形中每堆食物的量(小于10的非整数),编程计算这k条蚯蚓所能收集到的食物的最多总量。
输入描述 Input Description
输入数据由文件名为INPUT1.*的文本文件提供,共有n+1行。每行的两个数据之间用一个空格隔开。
●第1行是n、m和k的值。
- 接下来的n行依次是梯形的每一行的食物量a(i,1),a(i,2),…,a(i,m+i-1),i=1,2,…,n。
输出描述 Output Description
程序运行结束时,在屏幕上输出k蚯蚓条所能收集到的食物的最多总量。
样例输入 Sample Input
3 2 2
1 2
5 0 2
1 10 0 6
样例输出 Sample Output
26