zoukankan      html  css  js  c++  java
  • P4542 [ZJOI2011]营救皮卡丘

    传送门

    分析一下题目,发现每个点必须至少走过一次,并且对于一个人的路径,他摧毁的点编号一定是递增的

    并且在摧毁点 $i$ 之前,他不能经过 $i+1$ 到 $n$ 的点,考虑设 $dis[i][j],i<j$  表示从 $i$ 到 $j$,不经过比 $j$ 大的点的最短路径

    因为最终每个点都会被摧毁,那么一个人的总路程就是 $dis[0][p_1]sum_{i=2}^{n}dis[p_{i-1}][p_i]$ ($p_i$ 表示这个人摧毁的第 $i$ 个点),发现这其实就是最小覆盖问题

    所以直接套上去就好了,代码中把点的编号都 $+1$ 了,注意 $long long$

    #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,K,D[307][307];
    int main()
    {
        n=read()+1,m=read(),K=read();
        S=0,T=(n<<1)+1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++) D[i][j]=INF;
            D[i][i]=0;
        }
        int a,b,c;
        for(int i=1;i<=m;i++)
        {
            a=read()+1,b=read()+1,c=read();
            D[a][b]=D[b][a]=min(D[a][b],c);
        }
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(k<max(i,j)) D[i][j]=min(D[i][j],D[i][k]+D[k][j]);
        add(S,1,K,0);
        for(int i=2;i<=n;i++)
        {
            if(D[1][i]<INF) add(1,n+i,1,D[1][i]);
            add(n+i,T,1,0); add(S,i,1,0);
            for(int j=i+1;j<=n;j++)
                if(D[i][j]<INF) add(i,n+j,1,D[i][j]);
        }
        while(SPFA()) upd();
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    web十二讲,CSS样式
    web第十一讲,div与span
    web第十讲,CSS基础
    git 版本回退后再恢复
    git 变更远程仓库及在本地的别名
    使用FastClick插件,无法监听双击事件
    声明式编程的没落
    gradle 很棒
    评 PowerShell
    VB 的一些歧义(不断更新)
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/10805644.html
Copyright © 2011-2022 走看看