题目这么说:
给定一个由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=; 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=;i<NV;++i){
vis[i]=; d[i]=INF;
}
vis[vs]=; d[vs]=;
queue<int> que;
que.push(vs);
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=head[u]; i!=-; 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]=;
que.push(v);
}
}
}
vis[u]=;
}
return d[vt]!=INF;
}
int MCMF(){
int res=;
while(SPFA()){
int flow=INF,cost=;
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]^].cap+=flow;
cost+=flow*edge[pre[u]].cost;
}
res+=cost;
}
return res;
}
int a[][],idx[][];
int main(){
freopen("digit.in","r",stdin);
freopen("digit.out","w",stdout);
int m,n;
scanf("%d%d",&m,&n);
int cnt=;
for(int i=; i<n; ++i){
for(int j=; j<m+i; ++j) scanf("%d",&a[i][j]),idx[i][j]=cnt++;
}
vs=cnt*; vt=vs+; NV=vt+; NE=;
memset(head,-,sizeof(head));
for(int i=; i<n; ++i){
for(int j=; j<m+i; ++j){
addEdge(idx[i][j],idx[i][j]+cnt,,-a[i][j]);
if(i==) addEdge(vs,idx[i][j],,);
if(i==n-) addEdge(idx[i][j]+cnt,vt,,);
else{
addEdge(idx[i][j]+cnt,idx[i+][j],,);
addEdge(idx[i][j]+cnt,idx[i+][j+],,);
}
}
}
printf("%d\n",-MCMF()); vs=cnt*; vt=vs+; NV=vt+; NE=;
memset(head,-,sizeof(head));
for(int i=; i<n; ++i){
for(int j=; j<m+i; ++j){
addEdge(idx[i][j],idx[i][j]+cnt,INF,-a[i][j]);
if(i==) addEdge(vs,idx[i][j],,);
if(i==n-) addEdge(idx[i][j]+cnt,vt,INF,);
else{
addEdge(idx[i][j]+cnt,idx[i+][j],,);
addEdge(idx[i][j]+cnt,idx[i+][j+],,);
}
}
}
printf("%d\n",-MCMF()); vs=cnt*; vt=vs+; NV=vt+; NE=;
memset(head,-,sizeof(head));
for(int i=; i<n; ++i){
for(int j=; j<m+i; ++j){
addEdge(idx[i][j],idx[i][j]+cnt,INF,-a[i][j]);
if(i==) addEdge(vs,idx[i][j],,);
if(i==n-) addEdge(idx[i][j]+cnt,vt,INF,);
else{
addEdge(idx[i][j]+cnt,idx[i+][j],INF,);
addEdge(idx[i][j]+cnt,idx[i+][j+],INF,);
}
}
}
printf("%d",-MCMF());
return ;
}