洛谷P4013数字梯形问题——网络流24题

题目: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\n",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\n",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;
}

 

posted @ 2018-04-12 01:02  Zinn  阅读(185)  评论(0编辑  收藏  举报