zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    bash task list and interrupt
    bash字符串大小写转换方法
    Spectrum Mask
    OFDM中CP的优缺点
    模块边界使用寄存器来做数据的交互
    跨时钟域信号处理
    FPGA中一个Slice所含资源
    Verilog中if-else改写成case的方法
    同步序列的自相关与互相关
    TCP三次握手四次挥手
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/10805569.html
Copyright © 2011-2022 走看看