博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ZOJ - 3229 Shoot the Bullet (有源汇点上下界最大流)
阅读量:4986 次
发布时间:2019-06-12

本文共 2824 字,大约阅读时间需要 9 分钟。

题意:要在n天里给m个女生拍照,每个女生有拍照数量的下限Gi,每天有拍照数量的上限Di,每天当中每个人有拍照的上限Lij和Rij。求在满足限制的基础上,所有人最大能拍多少张照片。

分析:抛开限制,显然是一道最大流的问题,需要新建虚拟源点s和虚拟汇点t。加上上下界限制后就是有源汇点的上下界最大流问题。
要求解这个最大流,首先得保证上下界可行流有解。新增一个超级源点ss,超级汇点tt。点[1,n]视作n天,[n+1,n+m]视作m个女生。由源点s向[1,n]分别建容量为Di的弧,由于下界是0,所以不用分离出来。由[n+1,n+m]向汇点t建容量为INF - Gi的边,表示其下界为Gi,上界为正无穷。对于天数i中女生j的上下界Lij与Rij,从i向j+n建容量为Rij-Lij的弧。
记录每个点(包括s和t)的入流-出流的值cap[i],若cap[i]>0,由超级源点ss向其建容量为cap[i];若cap[i]<0,由该点向超级汇点tt建容量为-cap[i]的边。跑出ss到tt的最大流f,若f==由ss出发的所有边的流量上限之和,则说明有可行流。
在确保有可行流的基础上,该题要求的是最大流,做法是在残余网上跑出s到t的最大流,得到的最大流即为所求答案。
本题还需输出代表每天每人拍摄照片数的流量,则该流量 = 该弧流量下界 + 第二次跑出的自由流。

#include
using namespace std;using namespace std;typedef int LL;const int MAXN = 1505;const int INF = 0x3f3f3f3f;struct ISAP{ int n;//实际建图总点数(最好比图中总点数大一点) struct Edge{ int v,next; LL cap,flow; }edge[MAXN*100]; int cur[MAXN],pre[MAXN],gap[MAXN],path[MAXN],dep[MAXN]; int tot=0;//实际存储总边数 void init(int n){ this -> n =n; tot=0; memset(pre,-1,sizeof(pre)); } void AddEdge(int u,int v,LL w,LL rw=0)//加边 单向图三个参数 双向图四个 { edge[tot] = (Edge){v,pre[u],w,0}; pre[u]=tot++; edge[tot] = (Edge){u,pre[v],rw,0}; pre[v]=tot++; } bool bfs(int s,int t){//其实这个bfs可以融合到下面的迭代里,但是好像是时间要长 memset(dep,-1,sizeof(dep)); memset(gap,0,sizeof(gap)); gap[0]=1; dep[t]=0; queue
q; while(!q.empty()) q.pop(); q.push(t);//从汇点开始反向建层次图 while(!q.empty()){ int u=q.front(); q.pop(); for(int i=pre[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(dep[v]==-1&&edge[i^1].cap>edge[i^1].flow)//注意是从汇点反向bfs,但应该判断正向弧的余量 { dep[v]=dep[u]+1; gap[dep[v]]++; q.push(v); //if(v==s)//感觉这两句优化加了一般没错,但是有的题可能会错,所以还是注释出来,到时候视情况而定 //break; } } } return dep[s]!=-1; } LL isap(int s,int t){ bfs(s,t); memcpy(cur,pre,sizeof(pre)); int u=s; path[u]=-1; LL ans=0; while(dep[s]
0){ sum+= cap[i]; F.AddEdge(ss,i,cap[i]); } else{ F.AddEdge(i,tt,-cap[i]); } } int res = F.isap(ss,tt); if(res!=sum){ printf("-1\n"); } else{ res = F.isap(s,t); printf("%d\n",res); for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j){ if(id[i][j]){ printf("%d\n",F.edge[id[i][j]].flow+low[i][j]); } } } } printf("\n"); } return 0;}

转载于:https://www.cnblogs.com/xiuwenli/p/9637520.html

你可能感兴趣的文章
javascript基本函数
查看>>
前端公共库cdn服务推荐//提高加载速度/节省流量
查看>>
asp.net GridView多行表头的实现,合并表头
查看>>
C#套打
查看>>
PolyCluster: Minimum Fragment Disagreement Clustering for Polyploid Phasing 多聚类:用于多倍体的最小碎片不一致聚类...
查看>>
【每日进步】July 2012
查看>>
${sessionScope.user}的使用方法
查看>>
WCF开发框架形成之旅---结合代码生成工具实现快速开发
查看>>
Spring事务管理
查看>>
linux下mysql配置文件my.cnf详解
查看>>
08ssm三大框架整合以前步骤
查看>>
R语言学习笔记之八
查看>>
主动与被动监控 拓扑图组合图 自定义监控
查看>>
SQL总结(一)基本查询
查看>>
PDF分割--可脱离python环境执行,可传参数,可弹窗的PC端小工具
查看>>
layui中的html怎样接收后台的值,layui框架与SSM前后台交互的方法
查看>>
网络通信引擎ICE的使用
查看>>
js滚动事件实现滚动触底加载
查看>>
java框架--spring+stutrs2+mybatis整合
查看>>
Sliverlight调用Rest服务的一点思考和实践
查看>>