【CODEVS1033】蚯蚓的游戏问题(费用流)
2016-03-08 20:15
423 查看
题目描述
传送门题解
最大费用最大流问题,也是一个比较经典的模型。拆点
可以看做是入点和出点,容量为1,费用为每一个点的食物总量,以保证所有的点都只经过一次。
分别多建一个起点和终点,起点分别向第一行的点连一条边,容量为INF,费用为0,最后一行的点分别向终点连边,容量为INF,费用为0,只是表示可以流过。
从超级源向起点连一条边,容量为蚯蚓的数量,费用为0,从终点向超级汇连一条边,容量为蚯蚓的数量,费用为0;不难看出这是限制了蚯蚓的数量<=k。
用最大费用最大流求解即可。
代码
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int max_n=50; const int max_m=50; const int max_N=(max_n+2*max_m-1)*max_n+4; const int max_M=max_n*max_m*4; const int max_e=max_M*2; const int inf=1e9; int n,m,k,food,x1,x2,y1,y2,cnt,maxflow,maxcost,N; int next[max_e],point[max_N],v[max_e],remain[max_e],c[max_e],tot; int last[max_N],dis[max_N],vis[max_N]; queue <int> q; inline void addedge(int x,int y,int cap,int z){ ++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=cap; c[tot]=z; ++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0; c[tot]=-z; } inline int addflow(int s,int t){ int ans=inf,now=t; while (now!=s){ ans=min(ans,remain[last[now]]); now=v[last[now]^1]; } now=t; while (now!=s){ remain[last[now]]-=ans; remain[last[now]^1]+=ans; now=v[last[now]^1]; } return ans; } inline bool bfs(int s,int t){ memset(dis,128,sizeof(dis)); memset(vis,0,sizeof(vis)); dis[s]=0; vis[s]=true; while (!q.empty()) q.pop(); q.push(s); while (!q.empty()){ int now=q.front(); q.pop(); vis[now]=false; for (int i=point[now];i!=-1;i=next[i]) if (dis[v[i]]<dis[now]+c[i]&&remain[i]){ dis[v[i]]=dis[now]+c[i]; last[v[i]]=i; if (!vis[v[i]]){ vis[v[i]]=true; q.push(v[i]); } } } if (dis[t]<0) return false; int flow=addflow(s,t); maxflow+=flow; maxcost+=flow*dis[t]; return true; } inline void major(int s,int t){ maxflow=0; maxcost=0; while (bfs(s,t)); } int main(){ tot=-1; memset(point,-1,sizeof(point)); memset(next,-1,sizeof(next)); scanf("%d%d%d",&n,&m,&k); N=(n+2*m-1)*n+4; for (int i=1;i<=n;++i) for (int j=1;j<=m+i-1;++j){ scanf("%d",&food); ++cnt; x1=cnt*2+1; x2=cnt*2+2; addedge(x1,x2,1,food); if (i==1) addedge(2,x1,inf,0); if (i!=n){ y1=(cnt+m+i-1)*2+1; y2=(cnt+m+i)*2+1; addedge(x2,y1,inf,0); addedge(x2,y2,inf,0); } else addedge(x2,N-1,inf,0); } addedge(1,2,k,0); addedge(N-1,N,k,0); major(1,N); printf("%d\n",maxcost); }
总结
①最大费用最大流和最小费用最大流的区别在于:dis数组初始值为负无穷,dis[s]=0;判断条件的大于小于号方向相反;退出的条件不同。②算好点数和边数,避免数组爆掉。
③建图时一系列的编号想清楚。
相关文章推荐
- Unity3D启动报错的解决方案
- 第1周项目2—就拿胖子说事
- 第二周项目2-就拿胖子说事
- 因子分解机模型简介
- POI 实现对 Excel 文件读写
- 每周更新学习进度表
- 66. Plus One
- HDUACM2017
- javascript中定义事件的三种方式
- <Unity3D>上下左右 键控制人移动
- php五大运行模式CGI,FAST-CGI,CLI,ISAPI,APACHE模式浅谈
- Handler用法
- unity3d NGUI多场景共用界面制作
- 学习进度条
- C++运算符优先级
- POJ 2096 概率dp
- 算法训练 暗恋
- 银行业务-贷款
- HDU 1220 ( Cube )
- Android Fragment 真正的完全解析(上)