zoukankan      html  css  js  c++  java
  • 【BZOJ2324】[ZJOI2011]营救皮卡丘(网络流,费用流)

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

    题面

    BZOJ
    洛谷

    题解

    如果考虑每个人走的路径,就会很麻烦。
    转过来考虑每个人破坏的点集,这样子每个人可以得到一个上升的序列。
    预处理(dis[u][v])表示(u ightarrow 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
    ",Cost);
    	return 0;
    }
    
  • 相关阅读:
    Mongodb 查询时间类型
    Python更新所有pip package
    Python selenium on windows
    Redis cluster setup on windows
    CAP定理(theorem)
    error: Microsoft Visual C++ 14.0 is required when installing python package
    using RNGCryptoServiceProvider to generate random string
    <map>的使用
    二维vector的使用
    vector做形参时的三种传参方式
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10478028.html
Copyright © 2011-2022 走看看