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

COGS738 [网络流24题] 数字梯形(最小费用最大流)

2016-04-11 16:40 447 查看
题目这么说:


给定一个由n 行数字组成的数字梯形如下图所示。梯形的第一行有m 个数字。从梯形
的顶部的m 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶
至底的路径。
规则1:从梯形的顶至底的m条路径互不相交。
规则2:从梯形的顶至底的m条路径仅在数字结点处相交。
规则3:从梯形的顶至底的m条路径允许在数字结点相交或边相交。



对于给定的数字梯形,分别按照规则1,规则2,和规则3 计算出从梯形的顶至底的m
条路径,使这m条路径经过的数字总和最大。


对那三种情况分别建容量网络跑最小费用最大流,这个很容易的。。要注意题意上说的是顶部m个数字分别作为m条路径的出发点。

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 888
#define MAXM 888*888*2
struct Edge{
int u,v,cap,cost,next;
}edge[MAXM];
int head[MAXN];
int NV,NE,vs,vt;

void addEdge(int u,int v,int cap,int cost){
edge[NE].u=u; edge[NE].v=v; edge[NE].cap=cap; edge[NE].cost=cost;
edge[NE].next=head[u]; head[u]=NE++;
edge[NE].u=v; edge[NE].v=u; edge[NE].cap=0; edge[NE].cost=-cost;
edge[NE].next=head[v]; head[v]=NE++;
}
bool vis[MAXN];
int d[MAXN],pre[MAXN];
bool SPFA(){
for(int i=0;i<NV;++i){
vis[i]=0; d[i]=INF;
}
vis[vs]=1; d[vs]=0;
queue<int> que;
que.push(vs);
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(edge[i].cap && d[v]>d[u]+edge[i].cost){
d[v]=d[u]+edge[i].cost;
pre[v]=i;
if(!vis[v]){
vis[v]=1;
que.push(v);
}
}
}
vis[u]=0;
}
return d[vt]!=INF;
}
int MCMF(){
int res=0;
while(SPFA()){
int flow=INF,cost=0;
for(int u=vt; u!=vs; u=edge[pre[u]].u){
flow=min(flow,edge[pre[u]].cap);
}
for(int u=vt; u!=vs; u=edge[pre[u]].u){
edge[pre[u]].cap-=flow;
edge[pre[u]^1].cap+=flow;
cost+=flow*edge[pre[u]].cost;
}
res+=cost;
}
return res;
}
int a[22][44],idx[22][44];
int main(){
freopen("digit.in","r",stdin);
freopen("digit.out","w",stdout);
int m,n;
scanf("%d%d",&m,&n);
int cnt=0;
for(int i=0; i<n; ++i){
for(int j=0; j<m+i; ++j) scanf("%d",&a[i][j]),idx[i][j]=cnt++;
}
vs=cnt*2; vt=vs+1; NV=vt+1; NE=0;
memset(head,-1,sizeof(head));
for(int i=0; i<n; ++i){
for(int j=0; j<m+i; ++j){
addEdge(idx[i][j],idx[i][j]+cnt,1,-a[i][j]);
if(i==0) addEdge(vs,idx[i][j],1,0);
if(i==n-1) addEdge(idx[i][j]+cnt,vt,1,0);
else{
addEdge(idx[i][j]+cnt,idx[i+1][j],1,0);
addEdge(idx[i][j]+cnt,idx[i+1][j+1],1,0);
}
}
}
printf("%d\n",-MCMF());

vs=cnt*2; vt=vs+1; NV=vt+1; NE=0;
memset(head,-1,sizeof(head));
for(int i=0; i<n; ++i){
for(int j=0; j<m+i; ++j){
addEdge(idx[i][j],idx[i][j]+cnt,INF,-a[i][j]);
if(i==0) addEdge(vs,idx[i][j],1,0);
if(i==n-1) addEdge(idx[i][j]+cnt,vt,INF,0);
else{
addEdge(idx[i][j]+cnt,idx[i+1][j],1,0);
addEdge(idx[i][j]+cnt,idx[i+1][j+1],1,0);
}
}
}
printf("%d\n",-MCMF());

vs=cnt*2; vt=vs+1; NV=vt+1; NE=0;
memset(head,-1,sizeof(head));
for(int i=0; i<n; ++i){
for(int j=0; j<m+i; ++j){
addEdge(idx[i][j],idx[i][j]+cnt,INF,-a[i][j]);
if(i==0) addEdge(vs,idx[i][j],1,0);
if(i==n-1) addEdge(idx[i][j]+cnt,vt,INF,0);
else{
addEdge(idx[i][j]+cnt,idx[i+1][j],INF,0);
addEdge(idx[i][j]+cnt,idx[i+1][j+1],INF,0);
}
}
}
printf("%d",-MCMF());
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: