[网络流24题 #16]数字梯形问题
2014-01-28 10:36
573 查看
这是一道很经典的费用流题目,可以通过最大费用最大流实现
通过分析题目,我们很容易想到建模方法:
1、对于规则一,题目规定每一个节点只能访问一次,也就是说,实际上这个时候每一个点都有容量限制,所以我们必须把点i拆分成两个点Xi,Yi。此时每一条边的容量都是1,费用为改点的权值,此时只允许使用该节点一次,并且代价为权值。数字梯形是逐层向下的,并且每一个点可以向下面两个方向进行扩展,于是我们在这些点之间建立容量为1,费用为0的边。对于最顶层与最底层,我们分让两层分别与源点和汇点相连,容量同样是1,费用为0。(注意所有的边都是有向边,并且结点i与j相连是指Yi与Xj相连)
2、对于规则二,由于可以共点,所以就不用拆点了,源点与上层继续保持容量为1,其他的关联除了不用拆点外,其他都差不多,注意一下底层与汇点的容量限制改为无穷大即可。
3、对于规则三,由于边和节点都可以共用,此时没有必要把原网络销毁,直接在上一个规则的前提下修改每一条边的容量即可(注意源点与顶层节点之间的容量是不能变的,否则就无法满足是m条路径取得的最大值,其他边的容量改成无穷大即可)
通过分析题目,我们很容易想到建模方法:
1、对于规则一,题目规定每一个节点只能访问一次,也就是说,实际上这个时候每一个点都有容量限制,所以我们必须把点i拆分成两个点Xi,Yi。此时每一条边的容量都是1,费用为改点的权值,此时只允许使用该节点一次,并且代价为权值。数字梯形是逐层向下的,并且每一个点可以向下面两个方向进行扩展,于是我们在这些点之间建立容量为1,费用为0的边。对于最顶层与最底层,我们分让两层分别与源点和汇点相连,容量同样是1,费用为0。(注意所有的边都是有向边,并且结点i与j相连是指Yi与Xj相连)
2、对于规则二,由于可以共点,所以就不用拆点了,源点与上层继续保持容量为1,其他的关联除了不用拆点外,其他都差不多,注意一下底层与汇点的容量限制改为无穷大即可。
3、对于规则三,由于边和节点都可以共用,此时没有必要把原网络销毁,直接在上一个规则的前提下修改每一条边的容量即可(注意源点与顶层节点之间的容量是不能变的,否则就无法满足是m条路径取得的最大值,其他边的容量改成无穷大即可)
#include <cstdio> #include <iostream> #include <cstring> #include <vector> #include <queue> #define add(x) Q.push(x),v[x]=1 #define del(x) x=Q.front(),Q.pop(),v[x]=0 #define MaxN 40 #define MaxP 800 using namespace std; const int INF=~0U>>2; int map[MaxN][MaxN],num[MaxN][MaxN]; int head[MaxP],p[MaxP][2],d[MaxP]; int tot,n,m,s,t,TotP; bool v[MaxP]; struct edge { int v,cap,cost,next; edge(int x,int y,int c,int b): v(y),cap(c),cost(b),next(head[x]) { head[x]=tot++; } }; vector<edge> a; inline void AddEdge(int x,int y,int c,int b) { a.push_back(edge(x,y,c,b)); a.push_back(edge(y,x,0,-b)); } inline void InitFlow() { tot=0,a.clear(); memset(head,-1,sizeof(head)); } inline void init() { cin>>m>>n; for(int i=1;i<=n;i++) for(int j=1;j<(i+m);j++) scanf("%d",&map[i][j]), num[i][j]=++TotP; } inline bool LPFA() { int x,y; memset(v,0,sizeof(v)); for(int i=1;i<=t;i++) d[i]=-INF; queue<int> Q; add(s),d[s]=0; while(!Q.empty()) { del(x); for(int i=head[x];i!=-1;i=a[i].next) { y=a[i].v; if(a[i].cap&&d[x]+a[i].cost>d[y]) { d[y]=d[x]+a[i].cost; p[y][0]=i,p[y][1]=x; if(!v[y]) add(y); } } } return d[t]!=-INF; } inline int MaxCost() { int ans=0,flow; while(LPFA()) { flow=INF; for(int i=t;i!=s;i=p[i][1]) if(flow>a[p[i][0]].cap) flow=a[p[i][0]].cap; for(int i=t;i!=s;i=p[i][1]) a[p[i][0]].cap-=flow, a[p[i][0]^1].cap+=flow; ans+=d[t]*flow; } return ans; } inline void work() { /*Ques 1:*/ InitFlow(); t=TotP*2+1; for(int i=1;i<=m;i++) AddEdge(s,i,1,0); for(int i=1;i<=n;i++) for(int j=1;j<(i+m);j++) AddEdge(num[i][j],num[i][j]+TotP,1,map[i][j]); for(int i=1;i<n;i++) for(int j=1;j<(i+m);j++) AddEdge(num[i][j]+TotP,num[i+1][j],1,0), AddEdge(num[i][j]+TotP,num[i+1][j+1],1,0); for(int i=1;i<(n+m);i++) AddEdge(num [i]+TotP,t,1,0); cout<<MaxCost()<<endl; /*Ques 2:*/ InitFlow(); t=TotP+1; for(int i=1;i<=m;i++) AddEdge(s,i,1,0); for(int i=1;i<n;i++) for(int j=1;j<(m+i);j++) AddEdge(num[i][j],num[i+1][j],1,map[i][j]), AddEdge(num[i][j],num[i+1][j+1],1,map[i][j]); for(int i=1;i<(n+m);i++) AddEdge(num [i],t,INF,map [i]); cout<<MaxCost()<<endl; /*Ques 3:*/ for(int i=0;i<2*m;i+=2) a[i].cap=1, a[i+1].cap=0; for(int i=2*m;i<tot;i+=2) a[i].cap=INF, a[i+1].cap=0; cout<<MaxCost()<<endl; } int main() { init(); work(); return 0; }
相关文章推荐
- 【网络流24题-16】数字梯形问题
- 【网络流24题-16】数字梯形问题 费用流
- [网络流24题] 数字梯形问题
- 网络流24题 -No.16 数字梯形问题
- 网络流16数字梯形问题
- 线性规划与网络流24——数字梯形问题
- 网络流16数字梯形问题
- 【网络流24题】No.16 数字梯形问题 (不相交路径 最大费用流)
- 数字梯形问题[网络流24题之16]
- [网络流24题] 16 数字梯形(最大权不相交路径 ,最小费用最大流)
- [网络流24题]数字梯形问题
- 【网络流24题】数字梯形问题
- 线性规划与网络流24题之数字梯形问题 最大权不相交路径
- 【网络流24题16】数字梯形问题
- 网络流24题16. 数字梯形问题
- Libre 6010「网络流 24 题」数字梯形 (网络流,最大费用最大流)
- COGS738 [网络流24题] 数字梯形(最小费用最大流)
- 「网络流 24 题」数字梯形
- cogs 738. [网络流24题] 数字梯形
- loj6010「网络流 24 题」数字梯形