• P4553 80人环游世界


    传送门

    之前写了道星际竞速,这题一看就是星际竞速改版..

    考虑构建费用流模型

    把每个点拆成两个点 $u,v$

    $u$ 表示入点,$v$ 表示出点

    连边 $(u,T,a[i],0)$ ($a[i]$ 表示点 $i$ 需要的经过次数),表示节点 $i$ 要进入 $a[i]$ 次

    因为每个点都一定恰好进入 $a[i]$ 次,所以也一定有 $a[i]$ 个人从 $i$ 出发
    ,连边$(S,v,a[i],0)$ 表示一定有 $a[i]$ 个人有从点 $i$ 出发到其他点

    对于有边相连的两点 $(x,y)$,连边 $(v[x],u[y],INF,cst)$ 表示一个人从 $x$
    发到达点 $y$ 需要 $cst$ 代价

    因为人数有限制,所以新建一个点 $SS$ ,连边 $(S,SS,K,0)$,表示只有 $K$ 个人

    因为每个人可以任选位置作为起点,所以连边 $(SS,u[i],a[i],0)$

    这样最小费用最大流就是答案了

    因为只要跑一次费用流所以跑得还挺快...

    会构图了代码就不用讲了吧...

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=1e5+7,M=1e7+7,INF=1e9+7;
    int fir[N],from[M],to[M],val[M],cst[M],cntt=1;
    inline void add(int a,int b,int c,int d)
    {
        from[++cntt]=fir[a]; fir[a]=cntt;
        to[cntt]=b; val[cntt]=c; cst[cntt]=d;
        from[++cntt]=fir[b]; fir[b]=cntt;
        to[cntt]=a; val[cntt]=0; cst[cntt]=-d;
    }
    int dis[N],mif[N],pre[N],S,T;
    queue <int> q;
    bool inq[N];
    bool SPFA()
    {
        for(int i=S;i<=T;i++) dis[i]=INF;
        q.push(S); inq[S]=1; dis[S]=0,mif[S]=INF;
        while(!q.empty())
        {
            int x=q.front(); q.pop(); inq[x]=0;
            for(int i=fir[x];i;i=from[i])
            {
                int &v=to[i]; if(!val[i]||dis[v]<=dis[x]+cst[i]) continue;
                dis[v]=dis[x]+cst[i]; pre[v]=i;
                mif[v]=min(mif[x],val[i]);
                if(!inq[v]) q.push(v),inq[v]=1;
            }
        }
        return dis[T]<INF;
    }
    ll ans;
    void upd()
    {
        for(int now=T,i=pre[T]; now!=S; now=to[i^1],i=pre[now])
            val[i]-=mif[T],val[i^1]+=mif[T];
        ans+=1ll*mif[T]*dis[T];
    }
    
    int n,m,SS;
    int main()
    {
        n=read(),m=read(); int a;
        S=0,SS=(n<<1)+1,T=SS+1;
        add(S,SS,m,0);
        for(int i=1;i<=n;i++)
        {
            a=read();
            add(SS,n+i,a,0); add(n+i,T,a,0);
            add(S,i,a,0);
        }
        for(int i=1;i<n;i++)
            for(int j=i+1;j<=n;j++)
            {
                a=read();
                if(a!=-1) add(i,n+j,INF,a);
            }
        while(SPFA()) upd();
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    HDU 1010 Tempter of the Bone(DFS剪枝)
    HDU 1013 Digital Roots(九余数定理)
    HDU 2680 Choose the best route(反向建图最短路)
    HDU 1596 find the safest road(最短路)
    HDU 2072 单词数
    HDU 3790 最短路径问题 (dijkstra)
    HDU 1018 Big Number
    HDU 1042 N!
    NYOJ 117 求逆序数 (树状数组)
    20.QT文本文件读写
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/10805569.html
Copyright © 2020-2023  润新知