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

来源:互联网 发布:mac 网游 编辑:程序博客网 时间:2024/05/02 04:15

时间限制: 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/2struct 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[N][N],w[N][N],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[n][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;}
1 0
原创粉丝点击