NOIP 2016 费用流

飞扬的小鸟
【问题描述】
Flappy Bird是一款风靡一时的休闲手机游戏。玩家需要不断控制点击手机
屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙。如果
小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败。
现在小鸟们遇到了一个难题,他们遇到了一堵巨大的墙,墙上仅有m个洞供
他们通过,由于小鸟们的体型不同且墙上洞的形状也不同,所以每种体型的鸟通
过每个洞的时间都不同,鸟的体型共有n种,第i种体型的鸟通过第j个洞需要的
时间记为T(i,j),且一个洞必须前一只鸟通过之后后一只鸟才能开始通过。
从时刻0开始,鸟开始通过,而每一只鸟的等待时间为从时刻0到自己已经通
过洞的时间。现在知道了第i种体型的鸟有pi只,请求出使所有鸟都通过墙的最
少的等待时间之和。
【输入格式】
第1行包含两个正整数n和m,表示鸟的体型的种数和墙洞的数量。
第2行包含n个正整数,其中第i个数为pi,表示点第i种体型的鸟的只数。
接下来有n行,每行包含m个非负整数,这n行中的第i行的第j个数为t(i,j),
表示第i种体型的鸟通过第j个墙洞所需的时间。输入文件中每行相邻的两个数之
间均由一个空格隔开,行末均没有多余空格。
【输出格式】
输出仅一行包含一个整数,为总等待时间的最小值。
【输入输出样例】
bird.in bird.out
3 2
3 1 1
5 7
3 6
8 9
47


全国信息学奥林匹克联赛( NOIP2016 ) 复赛模拟 提高组
5 页 共 5
【数据范围】
每组数据的n、 m和p值如下:
对于 100%的数据, n<=40,m<=100,p<=800,t(i,j)<=1000(p 为鸟的总只数)
序号 n= m= p=
1 5 5 10
2 40 1 400
3 40 2 300
4 40 40 40
5 5 40 100
6 10 50 200
7 20 60 400
8 40 80 600
9 40 100 800
10 40 100 800


题解:

一个费用流的经典模型,对于这种问题,我们可以认为,对于一个洞,最后一个的鸟通
过的时间,只有他一个在等待,总答案贡献为 Time*1,倒数第二只鸟为 Time*2,一次类
推,于是我们可以建立出一张费用流的图
将源点连向 n 种鸟,费用 0,流量为这种鸟的 shuliang
将 m 个洞分别拆成 p 份,将这 m*p 个点连向汇点,费用 0,流量 1
将 n 种鸟分别连向 m*p 个洞的点,费用为 f(m,n)*1,f(m,n)*2,f(m,n)*3,……
,f(m,n)*p,流量为 1
然而 m*p 有 80000,n 有 40,连边有 3200000 条,所以需要优化,我们发现,一个洞的
f(m,n)*1 没有满流时,f(m,n)*2 一定没有用,于是我们可以一开始只将鸟连向每个洞的第
一个点,当一个点流满后,再在下一个点上建立新边,动态加边就可以过这道题了。



#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
const   int oo=1e9;  //无穷  
const   int mm=11111111;  //边  
const   int mn=888888;  //点  
int node,src,dest,edge;    
int ver[mm],flow[mm],cost[mm],nex[mm];    
int head[mn],dis[mn],p[mn],q[mn],vis[mn];    
/**这些变量基本与最大流相同,增加了  
 cost 表示边的费用,  
 p 记录可行流上节点对应的反向边  
 */    
inline void prepare(int _node,int _src,int _dest)  //预处理   点的个数  起点  终点  
{    
    node=_node,src=_src,dest=_dest;    
    for(int i=0; i<node; i++)head[i]=-1,vis[i]=0;    
    edge=0;    
}    
void addedge(int u,int v,int f,int c)    
{    
    ver[edge]=v,flow[edge]=f,cost[edge]=c,nex[edge]=head[u],head[u]=edge++;    
    ver[edge]=u,flow[edge]=0,cost[edge]=-c,nex[edge]=head[v],head[v]=edge++;    
}    
/**以上同最大流*/    
/**spfa 求最短路,并用 p 记录最短路上的边*/    
bool spfa()    
{    
    int i,u,v,l,r=0,tmp;    
    for(i=0; i<node; ++i)dis[i]=oo;    
    dis[q[r++]=src]=0;    
    p[src]=p[dest]=-1;    
    for(l=0; l!=r; (++l>=mn)?l=0:l)    
        for(i=head[u=q[l]],vis[u]=0; i>=0; i=nex[i])    
            if(flow[i]&&dis[v=ver[i]]>(tmp=dis[u]+cost[i]))    
            {    
                dis[v]=tmp;    
                p[v]=i^1;    
                if(vis[v]) continue;    
                vis[q[r++]=v]=1;    
                if(r>=mn)r=0;    
            }    
    return p[dest]>-1;    
}    
int num[45],cot[45][105],n,m,sum;
/**源点到汇点的一条最短路即可行流,不断的找这样的可行流*/    
int SpfaFlow()    
{    
    int i,ret=0,delta;    
    while(spfa())    
    {    
        for(i=p[dest],delta=oo; i>=0; i=p[ver[i]])    
            if(flow[i^1]<delta)delta=flow[i^1];    
        for(i=p[dest]; i>=0; i=p[ver[i]])    
            flow[i]+=delta,flow[i^1]-=delta;    
        ret+=delta*dis[dest];    
        int pt=ver[p[dest]];
        int x=(pt-n-1)%sum+1,y=(pt-n+sum-1)/sum;
        if(x==sum)break;
        for(int i=1;i<=n;i++)addedge(i,n+(y-1)*sum+x+1,1,(x+1)*cot[i][y]);
    }    
    return ret;    
} 
int main(){
	int i,j;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)scanf("%d",&num[i]),sum+=num[i];
	prepare(n+sum*m+2,0,n+sum*m+1);
	for(i=1;i<=n;i++){
		addedge(0,i,num[i],0);
		for(j=1;j<=m;j++)scanf("%d",&cot[i][j]),addedge(i,n+(j-1)*sum+1,1,cot[i][j]);
	}
	for(i=1;i<=sum;i++){
		for(j=1;j<=m;j++)addedge(n+(j-1)*sum+i,n+sum*m+1,1,0);
	}
	printf("%d\n",SpfaFlow());
	return 0;
} 
/*
3 2
3 1 1
5 7
3 6
8 9

47
*/




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值