题目:https://www.luogu.org/problemnew/show/P4013
最大费用最大流裸题;
注意:在第二种情况中,底层所有点连向汇点的边容量应该为inf,因为可以有多条路径结束在同一个点。(为这个调了半天...)
代码如下:
#include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; queue<int>q; int const MAXN=1605,inf=1e9; int n,m,head[MAXN],ct=1,cnt,incf[MAXN],dis[MAXN],pre[MAXN],nd[MAXN],bh[25][45],t; bool vis[MAXN]; struct N{ int hd,to,next,w,v; N(int h=0,int t=0,int n=0,int w=0,int v=0):hd(h),to(t),next(n),w(w),v(v) {} }edge[MAXN<<1]; void add(int x,int y,int w,int v) { edge[++ct]=N(x,y,head[x],w,v);head[x]=ct; edge[++ct]=N(y,x,head[y],-w,0);head[y]=ct; } void clr() { ct=1; memset(head,0,sizeof head); } bool spfa() { memset(pre,0,sizeof pre); memset(dis,-3,sizeof dis); // memset(incf,3,sizeof incf); while(q.size())q.pop(); dis[0]=0;vis[0]=1;q.push(0);incf[0]=inf; while(q.size()) { int x=q.front();q.pop(); // printf("x=%d ",x); // cout<<x<<endl; vis[x]=0; for(int i=head[x];i;i=edge[i].next) { int u=edge[i].to; if(dis[u]<dis[x]+edge[i].w&&edge[i].v) { dis[u]=dis[x]+edge[i].w; pre[u]=i; incf[u]=min(incf[x],edge[i].v); if(!vis[u])vis[u]=1,q.push(u); } } } return pre[t]; } void mcf() { long long ans=0; while(spfa()) { ans+=incf[t]*dis[t]; // cout<<incf[t]<<" "<<dis[t]<<endl; for(int i=pre[t];i;i=pre[edge[i].hd]) { edge[i].v-=incf[t]; edge[i^1].v+=incf[t]; } } printf("%lld ",ans); } void cl1() { clr(); for(int i=1;i<=n;i++) add(0,bh[1][i],0,1); for(int i=1;i<m;i++) for(int j=1;j<n+i;j++) { int x=bh[i][j]; int u1=bh[i+1][j],u2=bh[i+1][j+1]; add(x+cnt,u1,0,1); add(x+cnt,u2,0,1); add(x,x+cnt,nd[x],1); } for(int i=1;i<n+m;i++) { int x=bh[m][i]; add(x,x+cnt,nd[x],1); add(x+cnt,t,0,1); } mcf(); } void cl2() { clr(); for(int i=1;i<=n;i++) add(0,bh[1][i],0,1);//!inf for(int i=1;i<m;i++) for(int j=1;j<n+i;j++) { int x=bh[i][j]; int u1=bh[i+1][j],u2=bh[i+1][j+1]; add(x+cnt,u1,0,1); add(x+cnt,u2,0,1); add(x,x+cnt,nd[x],inf); } for(int i=1;i<n+m;i++) { int x=bh[m][i]; add(x,x+cnt,nd[x],inf); add(x+cnt,t,0,inf);//inf!!! } mcf(); } void cl3() { clr(); for(int i=1;i<=n;i++) add(0,bh[1][i],0,1);//!inf for(int i=1;i<m;i++) for(int j=1;j<n+i;j++) { int x=bh[i][j]; int u1=bh[i+1][j],u2=bh[i+1][j+1]; add(x+cnt,u1,0,inf); add(x+cnt,u2,0,inf); add(x,x+cnt,nd[x],inf); } for(int i=1;i<n+m;i++) { int x=bh[m][i]; add(x,x+cnt,nd[x],inf); add(x+cnt,t,0,inf); } mcf(); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) for(int j=1;j<n+i;j++) { int x; scanf("%d",&x); nd[++cnt]=x; bh[i][j]=cnt; } t=2*cnt+1; cl1(); cl2(); cl3(); return 0; }