COGS738 [网络流24题] 数字梯形(最小费用最大流)
题目这么说:
给定一个由n 行数字组成的数字梯形如下图所示。梯形的第一行有m 个数字。从梯形
的顶部的m 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶
至底的路径。
规则1:从梯形的顶至底的m条路径互不相交。
规则2:从梯形的顶至底的m条路径仅在数字结点处相交。
规则3:从梯形的顶至底的m条路径允许在数字结点相交或边相交。
对于给定的数字梯形,分别按照规则1,规则2,和规则3 计算出从梯形的顶至底的m
条路径,使这m条路径经过的数字总和最大。
对那三种情况分别建容量网络跑最小费用最大流,这个很容易的。。要注意题意上说的是顶部m个数字分别作为m条路径的出发点。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 #define INF (1<<30) 7 #define MAXN 888 8 #define MAXM 888*888*2 9 struct Edge{ 10 int u,v,cap,cost,next; 11 }edge[MAXM]; 12 int head[MAXN]; 13 int NV,NE,vs,vt; 14 15 void addEdge(int u,int v,int cap,int cost){ 16 edge[NE].u=u; edge[NE].v=v; edge[NE].cap=cap; edge[NE].cost=cost; 17 edge[NE].next=head[u]; head[u]=NE++; 18 edge[NE].u=v; edge[NE].v=u; edge[NE].cap=0; edge[NE].cost=-cost; 19 edge[NE].next=head[v]; head[v]=NE++; 20 } 21 bool vis[MAXN]; 22 int d[MAXN],pre[MAXN]; 23 bool SPFA(){ 24 for(int i=0;i<NV;++i){ 25 vis[i]=0; d[i]=INF; 26 } 27 vis[vs]=1; d[vs]=0; 28 queue<int> que; 29 que.push(vs); 30 while(!que.empty()){ 31 int u=que.front(); que.pop(); 32 for(int i=head[u]; i!=-1; i=edge[i].next){ 33 int v=edge[i].v; 34 if(edge[i].cap && d[v]>d[u]+edge[i].cost){ 35 d[v]=d[u]+edge[i].cost; 36 pre[v]=i; 37 if(!vis[v]){ 38 vis[v]=1; 39 que.push(v); 40 } 41 } 42 } 43 vis[u]=0; 44 } 45 return d[vt]!=INF; 46 } 47 int MCMF(){ 48 int res=0; 49 while(SPFA()){ 50 int flow=INF,cost=0; 51 for(int u=vt; u!=vs; u=edge[pre[u]].u){ 52 flow=min(flow,edge[pre[u]].cap); 53 } 54 for(int u=vt; u!=vs; u=edge[pre[u]].u){ 55 edge[pre[u]].cap-=flow; 56 edge[pre[u]^1].cap+=flow; 57 cost+=flow*edge[pre[u]].cost; 58 } 59 res+=cost; 60 } 61 return res; 62 } 63 int a[22][44],idx[22][44]; 64 int main(){ 65 freopen("digit.in","r",stdin); 66 freopen("digit.out","w",stdout); 67 int m,n; 68 scanf("%d%d",&m,&n); 69 int cnt=0; 70 for(int i=0; i<n; ++i){ 71 for(int j=0; j<m+i; ++j) scanf("%d",&a[i][j]),idx[i][j]=cnt++; 72 } 73 vs=cnt*2; vt=vs+1; NV=vt+1; NE=0; 74 memset(head,-1,sizeof(head)); 75 for(int i=0; i<n; ++i){ 76 for(int j=0; j<m+i; ++j){ 77 addEdge(idx[i][j],idx[i][j]+cnt,1,-a[i][j]); 78 if(i==0) addEdge(vs,idx[i][j],1,0); 79 if(i==n-1) addEdge(idx[i][j]+cnt,vt,1,0); 80 else{ 81 addEdge(idx[i][j]+cnt,idx[i+1][j],1,0); 82 addEdge(idx[i][j]+cnt,idx[i+1][j+1],1,0); 83 } 84 } 85 } 86 printf("%d\n",-MCMF()); 87 88 vs=cnt*2; vt=vs+1; NV=vt+1; NE=0; 89 memset(head,-1,sizeof(head)); 90 for(int i=0; i<n; ++i){ 91 for(int j=0; j<m+i; ++j){ 92 addEdge(idx[i][j],idx[i][j]+cnt,INF,-a[i][j]); 93 if(i==0) addEdge(vs,idx[i][j],1,0); 94 if(i==n-1) addEdge(idx[i][j]+cnt,vt,INF,0); 95 else{ 96 addEdge(idx[i][j]+cnt,idx[i+1][j],1,0); 97 addEdge(idx[i][j]+cnt,idx[i+1][j+1],1,0); 98 } 99 } 100 } 101 printf("%d\n",-MCMF()); 102 103 vs=cnt*2; vt=vs+1; NV=vt+1; NE=0; 104 memset(head,-1,sizeof(head)); 105 for(int i=0; i<n; ++i){ 106 for(int j=0; j<m+i; ++j){ 107 addEdge(idx[i][j],idx[i][j]+cnt,INF,-a[i][j]); 108 if(i==0) addEdge(vs,idx[i][j],1,0); 109 if(i==n-1) addEdge(idx[i][j]+cnt,vt,INF,0); 110 else{ 111 addEdge(idx[i][j]+cnt,idx[i+1][j],INF,0); 112 addEdge(idx[i][j]+cnt,idx[i+1][j+1],INF,0); 113 } 114 } 115 } 116 printf("%d",-MCMF()); 117 return 0; 118 }