• 【BZOJ1927】星际竞速(SCOI2010)-费用流+拆点


    测试地址:星际竞速
    做法:本题需要用到费用流+拆点。
    分析题目中要求的路径,我们发现在一条满足要求的路径中,除起点那颗不和任何点连通的点外,所有点的入度都是1,那么这些入度从哪里来呢?一是从某个星球飞过来,二是从某个星球跳过来(这话说的……)。因为一开始我们也是从一个星球跳到某个星球上的,所以我们把所有跳的决策都看做从起点跳过去,那么每个点的入度来源就只有两个,一是从某个星球飞过来,二是从起点跳过来。因为路径上每个点的出度也只有1,那么我们显然可以把一个点拆成两个点,一个表示出度点,一个表示入度点。那么我们可以这样建图:
    从源点向每个出度点连容量为1,费用为0的边,再从源点向每个入度点连容量为1,费用为跳跃到该点的定位时间,然后从每个入度点向汇点连容量为1,费用为0的边,最后对于原来一条可以走的边(x,y),从x的出度点向y的入度点连容量为1,费用为所需时间的边。这样每一份流量都代表一次决策,即从某个星球飞向另一个星球,或直接跳跃到某个星球,那么在最大流的情况下能得到的最小费用就是我们要求的答案了,所以直接做即可。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int inf=1000000000;
    int n,m,S,T,first[2010]={0},tot=1;
    int dis[2010],laste[2010],last[2010];
    queue<int> Q;
    bool vis[2010];
    struct edge
    {
        int v,next,f,c;
    }e[50010];
    
    void insert(int a,int b,int f,int c)
    {
        e[++tot].v=b,e[tot].next=first[a],e[tot].f=f,e[tot].c=c,first[a]=tot;
        e[++tot].v=a,e[tot].next=first[b],e[tot].f=0,e[tot].c=-c,first[b]=tot;
    }
    
    void init()
    {
        scanf("%d%d",&n,&m);
        S=(n<<1)+1,T=(n<<1)+2;
        for(int i=1;i<=n;i++)
        {
            int t;
            scanf("%d",&t);
            insert(S,i,1,0);
            insert(S,n+i,1,t);
            insert(n+i,T,1,0);
        }
        for(int i=1;i<=m;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            if (u>v) swap(u,v);
            insert(u,n+v,1,w);
        }
    }
    
    bool spfa()
    {
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=T;i++)
            dis[i]=inf;
        dis[S]=0;
        vis[S]=1;
        Q.push(S);
        while(!Q.empty())
        {
            int v=Q.front();Q.pop();
            for(int i=first[v];i;i=e[i].next)
                if (e[i].f&&dis[e[i].v]>dis[v]+e[i].c)
                {
                    laste[e[i].v]=i;
                    last[e[i].v]=v;
                    dis[e[i].v]=dis[v]+e[i].c;
                    if (!vis[e[i].v]) Q.push(e[i].v),vis[e[i].v]=1;
                }
            vis[v]=0;
        }
        return dis[T]!=inf;
    }
    
    void mincost()
    {
        int minc=0;
        while(spfa())
        {
            int x=T,maxf=inf;
            while(x!=S)
            {
                maxf=min(maxf,e[laste[x]].f);
                x=last[x];
            }
            x=T;
            while(x!=S)
            {
                e[laste[x]].f-=maxf;
                e[laste[x]^1].f+=maxf;
                x=last[x];
            }
            minc+=maxf*dis[T];
        }
        printf("%d",minc);
    }
    
    int main()
    {
        init();
        mincost();
    
        return 0;
    }
  • 相关阅读:
    shell编程:字符串处理方式
    shell编程:变量替换
    export的用法
    docker stack利用secrets启动wordpress
    docker swarm创建swarm集群
    docker x509: certificate has expired or is not yet valid
    docker-compose的scale的用法
    字符串函数-unquote()函数
    Sass-@each
    Sass-@while
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793426.html
Copyright © 2020-2023  润新知