您的位置:首页 > 理论基础 > 计算机网络

[网络流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条路径取得的最大值,其他边的容量改成无穷大即可)

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  费用流