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

48 篇文章 0 订阅
23 篇文章 0 订阅

时间限制: 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[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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值