您的位置:首页 > 理论基础 > 计算机网络

Codevs_P1033 蚯蚓的游戏问题(拆点网络流+最小费用流)

2015-12-31 22:22 801 查看
时间限制: 1 s

空间限制: 128000 KB

题目等级 : 大师 Master

题目描述 Description

在一块梯形田地上,一群蚯蚓在做收集食物游戏。蚯蚓们把梯形田地上的食物堆积整理如下:



它们把食物分成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

#include<cstdio>
#include<climits>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
#define N 151
#define INF INT_MAX/2
struct work{
struct Edge{
int fr,to,flow,cap,cost;
Edge(int f,int t,int fl,int ca,int co):fr(f),to(t),flow(fl),cap(ca),cost(co){}
};
vector<Edge> edge;vector<int> g[N*N];
int p[N*N],v

,w

,a[N*N],d[N*N];
int n,m,k,mm,vv,ans,s,t;

int in(){
int x=0;char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}

void Add_Edge(int fr,int to,int cap,int cost){
edge.push_back(Edge(fr,to,0,cap,cost));
edge.push_back(Edge(to,fr,0,0,-cost));
mm=edge.size();
g[fr].push_back(mm-2);
g[to].push_back(mm-1);
return;
}

void init(){
scanf("%d%d%d",&n,&m,&k);vv=0;
for(int i=1;i<=n;i++)
for(int j=1;j<m+i;j++)
v[i][j]=in(),w[i][j]=++vv;
/*  for(int i=1;i<=n;i++)
for(int j=1;j<m+i;j++)
printf("%d ",w[i][j]);
printf("%d ",vv);*/
for(int i=1;i<=n;i++)
for(int j=1;j<m+i;j++){
Add_Edge(w[i][j],w[i][j]+vv,1,0);Add_Edge(w[i][j],w[i][j]+vv,1,-v[i][j]);
if(i<n){
Add_Edge(w[i][j]+vv,w[i+1][j],1,0);Add_Edge(w[i][j]+vv,w[i+1][j+1],1,0);
}
}
s=0,t=vv*2+1;
for(int i=1;i<=m;i++) Add_Edge(s,w[1][i],1,0);
for(int i=1;i<m+n;i++) Add_Edge(w
[i]+vv,t,1,0);
return;
}

int spfa(){
int x;
queue<int> q;int b[N*N];
for(int i=1;i<=n;i++)
for(int j=1;j<m+i;j++){
d[w[i][j]]=INF,b[w[i][j]]=false;
d[w[i][j]+vv]=INF,b[w[i][j]+vv]=false;
}
b[t]=false,d[t]=INF;b[s]=true,d[s]=0,a[s]=1;q.push(s);
while(!q.empty()){
x=q.front();q.pop();b[x]=false;
for(int i=0;i<g[x].size();i++){
Edge& e=edge[g[x][i]];
if(e.cap>e.flow&&d[e.to]>d[x]+e.cost){
d[e.to]=d[x]+e.cost;
p[e.to]=g[x][i];
a[e.to]=min(a[x],e.cap-e.flow);
if(!b[e.to])    {b[e.to]=true;q.push(e.to);}
}
}
}
if(d[t]==INF) return 0;
ans+=d[t]*a[t];
for(x=t;x!=s;x=edge[p[x]].fr){
edge[p[x]].flow+=a[t],edge[p[x]^1].flow-=a[t];
}
return 1;
}

void solve(){
init();
while(k--&&spfa());
printf("%d",-ans);
return;
}
}s;
int main(){
s.solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: