首页 > 其他 > 详细

【BZOJ2324】[ZJOI2011]营救皮卡丘(网络流,费用流)

时间:2019-03-05 17:21:38      阅读:157      评论:0      收藏:0      [点我收藏+]

【BZOJ2324】[ZJOI2011]营救皮卡丘(网络流,费用流)

题面

BZOJ
洛谷

题解

如果考虑每个人走的路径,就会很麻烦。
转过来考虑每个人破坏的点集,这样子每个人可以得到一个上升的序列。
预处理\(dis[u][v]\)表示\(u\rightarrow v\)在不经过标号大于\(max\{u,v\}\)的点的情况下的最短路。
这个可以\(Floyd\)预处理。
不妨把\(0\)号点加入到每个人的序列开头,这样子一个假设一个人的序列是\(P\),那么他经过的所有边的和就是\(\sum_{i=2}^{|P|}dis[P_{i-1}][P_i]\)
这样子就可以构建一个\(DAG\),然后要找出不超过\(k\)条路径来覆盖,对于两个点\(i,j,i<j\),从\(i\)\(j\)的费用为\(dis[i][j]\)
为了强制每个点都被访问过,把点拆成两个,因为是路径覆盖,所以每个点入度出度一进一出。
把每个点拆成入点和出点,出点作为\(i\),向其他点\(j\)的出点连边。
然后入点向\(T\)连边,表示必须有一个前驱,然后\(S\)向出点连边,表示必须有个后继。
然后\(S\)\(0\)的出点连边,容量为\(K\),表示\(K\)条路径。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MAX 155
const int inf=150100;
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
namespace MCMF
{
    const int MAXM=1000000,MAXN=1000;
    struct Line{int v,next,w,fy;}e[MAXM];
    int h[MAXN],cnt=2;
    inline void Add(int u,int v,int w,int fy)
    {
        e[cnt]=(Line){v,h[u],w,fy};h[u]=cnt++;
        e[cnt]=(Line){u,h[v],0,-fy};h[v]=cnt++;
    }
    int dis[MAXN],pe[MAXN],pv[MAXN],Cost,Flow;
    bool vis[MAXN];queue<int> Que;
    int S=MAXN-2,T=MAXN-1;
    bool SPFA()
    {
        memset(dis,63,sizeof(dis));dis[S]=0;
        Que.push(S);vis[S]=true;
        while(!Que.empty())
        {
            int u=Que.front();Que.pop();
            for(int i=h[u];i;i=e[i].next)
            {
                int v=e[i].v;if(!e[i].w)continue;
                if(dis[u]+e[i].fy<dis[v])
                {
                    dis[v]=dis[u]+e[i].fy;pe[v]=i,pv[v]=u;
                    if(!vis[v])vis[v]=true,Que.push(v);
                }
            }
            vis[u]=false;
        }
        if(dis[T]>=1e9)return false;
        int flow=1e9;
        for(int i=T;i!=S;i=pv[i])flow=min(flow,e[pe[i]].w);
        for(int i=T;i!=S;i=pv[i])e[pe[i]].w-=flow,e[pe[i]^1].w+=flow;
        Flow+=flow;Cost+=dis[T]*flow;
        return true;
    }
}
using namespace MCMF;
int n,m,K,g[MAX][MAX];
int main()
{
    n=read();m=read();K=read();
    memset(g,63,sizeof(g));for(int i=0;i<=n;++i)g[i][i]=0;
    for(int i=1,u,v;i<=m;++i)u=read(),v=read(),g[u][v]=g[v][u]=min(g[u][v],read());
    for(int k=0;k<=n;++k)
        for(int i=0;i<=n;++i)
            for(int j=0;j<=n;++j)
                if(k<=i||k<=j)g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
    Add(S,0+n+1,K,0);
    for(int i=1;i<=n;++i)Add(S,i+n+1,1,0),Add(i,T,1,0);
    for(int i=0;i<=n;++i)
        for(int j=i+1;j<=n;++j)
            Add(i+n+1,j,1,g[i][j]);
    while(SPFA());printf("%d\n",Cost);
    return 0;
}

【BZOJ2324】[ZJOI2011]营救皮卡丘(网络流,费用流)

原文:https://www.cnblogs.com/cjyyb/p/10478028.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!