【网络流24题】数字梯形

Description

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

P

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

Input

第1 行中有2个正整数m和n(m,n<=20),分别表示数字梯形的第一行有m个数字,共有n 行。
接下来的n 行是数字梯形中各行的数字。第1 行有m个数字,第2 行有m+1 个数字,…。

Output

将按照规则1,规则2,和规则3 计算出的最大数字总和输出,每行一个最大总和。

Sample Input

2 5
2 3
3 4 5
9 10 9 1
1 1 10 1 1
1 1 10 12 1 1

Sample Output

66
75
77

将每个点一分为二,这个点的上的值赋给连接这两个的边的费用,其他边按照题目的要求来连,费用都为0
题目有三问,就跑三遍最大费用最大流。
第一问:每条边的容量都为1。
第二问:拆开的两个点之间的容量为正无穷,与汇点的容量为正无穷。
第三问:除了源点之外其他边的容量都为正无穷。
(代码巨吃藕无比)


#include<set>
#include<map>
#include<queue>
#include<stack>
#include<ctime>
#include<cmath>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 1999999999
using namespace std;
struct data{
  int nex,to,w,c;
}e[10000],g1[10000],g2[10000],g3[10000];
int a[30][30],head1[800],head2[800],head3[800],head[800],edge1=-1,edge2=-1,edge3=-1,dis[800],vis[800],pre[800];
void add1(int from,int to,int w,int c){
  g1[++edge1].nex=head1[from];
  g1[edge1].to=to,g1[edge1].w=w,g1[edge1].c=c;
  head1[from]=edge1;
}
void add2(int from,int to,int w,int c){
  g2[++edge2].nex=head2[from];
  g2[edge2].to=to,g2[edge2].w=w,g2[edge2].c=c;
  head2[from]=edge2;
}
void add3(int from,int to,int w,int c){
  g3[++edge3].nex=head3[from];
  g3[edge3].to=to,g3[edge3].w=w,g3[edge3].c=c;
  head3[from]=edge3;
}
bool SPFA(int s,int t){
  queue<int>q;
  q.push(s);
  memset(dis,127,sizeof(dis));
  memset(pre,0,sizeof(pre));
  int zd=dis[0];
  vis[s]=1;dis[s]=0;
  while(!q.empty()){
    int u=q.front();q.pop();
    vis[u]=0;
    for(int i=head[u];i!=-1;i=e[i].nex){
      if(e[i].w>0 && dis[e[i].to]>dis[u]+e[i].c){
    dis[e[i].to]=dis[u]+e[i].c;
    pre[e[i].to]=i;
    if(!vis[e[i].to]) vis[e[i].to]=1,q.push(e[i].to);
      }
    }
  }
  if(dis[t]==zd) return 0;
  else return 1;
}
int end(int s,int t){
  int p=0,sum=1999999999,ans=0;
  for(int u=t;u!=s;u=e[p^1].to)
    p=pre[u],sum=min(sum,e[p].w);
  for(int u=t;u!=s;u=e[p^1].to){
    p=pre[u];
    e[p].w-=sum;
    e[p^1].w+=sum;
    ans+=sum*e[p].c;
  }
  return ans;
}
int solve(int s,int t){
  int flow=0;
  while(SPFA(s,t)) flow+=end(s,t);
  return -flow;
}
int main()
{
  freopen("!.in","r",stdin);
  freopen("!.out","w",stdout);
  memset(head,-1,sizeof(head));
  memset(head1,-1,sizeof(head1));
  memset(head2,-1,sizeof(head2));
  memset(head3,-1,sizeof(head3));
  int n,m;scanf("%d%d",&n,&m);
  int s=0,sum=(n+n+m-1)*m/2,t=(n+n+m-1)*m+1;
  for(int i=1;i<=m;i++)
    for(int j=1;j<n+i;j++){
      scanf("%d",&a[i][j]);
      int s1=(n+n+i-2)*(i-1)/2+j;
      add1(s1,s1+sum,1,-a[i][j]),add1(s1+sum,s1,0,a[i][j]);
      add2(s1,s1+sum,inf,-a[i][j]),add2(s1+sum,s1,0,a[i][j]);
      add3(s1,s1+sum,inf,-a[i][j]),add3(s1+sum,s1,0,a[i][j]);
    }
  for(int i=1;i<=n;i++)
    add1(s,i,1,0),add1(i,s,0,0),add2(s,i,1,0),add2(i,s,0,0),add3(s,i,1,0),add3(i,s,0,0);
  for(int i=1;i<m;i++)
    for(int j=1;j<n+i;j++){
      int s=(n+n+i-1)*i/2+j,s1=(n+n+i-2)*(i-1)/2+j;
      add1(s1+sum,s,1,0),add1(s,s1+sum,0,0);
      add1(s1+sum,s+1,1,0),add1(s+1,s1+sum,0,0);
      add2(s1+sum,s,1,0),add2(s,s1+sum,0,0);
      add2(s1+sum,s+1,1,0),add2(s+1,s1+sum,0,0);
      add3(s1+sum,s,inf,0),add3(s,s1+sum,0,0);
      add3(s1+sum,s+1,inf,0),add3(s+1,s1+sum,0,0);
    }
  for(int i=1;i<n+m;i++){
    int s=(n+n+m-2)*(m-1)/2;
    add1(s+i+sum,t,1,0),add1(t,s+i+sum,0,0);
    add2(s+i+sum,t,inf,0),add2(t,s+i+sum,0,0);
    add3(s+i+sum,t,inf,0),add3(t,s+i+sum,0,0);
  }
  memcpy(e,g1,sizeof(e));
  memcpy(head,head1,sizeof(head));
  printf("%d
",solve(s,t));
  memcpy(head,head2,sizeof(head));
  memcpy(e,g2,sizeof(e));
  printf("%d
",solve(s,t));
  memcpy(head,head3,sizeof(head));
  memcpy(e,g3,sizeof(e));
  printf("%d
",solve(s,t));
}
原文地址:https://www.cnblogs.com/pantakill/p/6613458.html