zoukankan      html  css  js  c++  java
  • 【UOJ#32】【UR #2】跳蚤公路(最短路)

    【UOJ#32】【UR #2】跳蚤公路(最短路)

    题面

    UOJ

    题解

    不难发现要求的就是是否存在负环。也就是我们只需要找到所有的负的简单环,很容易就可以想到维护路径上和(x)相关的内容,即维护一下(u)(v)路径上,含有(kx)的路径的最小的(b)。这个可以用(Floyd)(O(n^5))的复杂度中求解。这样子我们用(f[u][u][k])就知道了一个包含了(u)的,且(x)系数为(k)的最小的环,求出其负环的值域范围,接着其能够到达的所有点都会收到这个负环的限制。
    我们的主要目的是找出简单负环,找负环可以用(Bellman-Ford)算法,设(f[t][v])表示从(1)号点开始走不超过(t)步,到达(v)的最短路。因为最短路是简单路径,不会有重复点,所谓(f[t-1][v]=f[t][v])。否则如果不等必定存在负环。
    注意这个只能检测负环是否存在,我们还要考虑负环会造成的影响,如果一个点(f[t][v]<f[t-1][v]),证明这个点受到了负环的影响,同理其所有能够到达的点也能够受到负环的影响。
    那么我们把这个想法拓展一步,变为(f[t][v][k]),表示走了(t)步,到(v)(x)的系数为(k)的最短路。
    那么如果存在负环,就要满足:

    [min{kx+f[n][v][k]}ge min{jx+f[n-1][v][j]} ]

    那么只需要把这个数组搞出来,然后就可以解(x)范围了。

    窝代码是抄的。。。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define ll long long
    #define MAX 105
    #define pi pair<ll,ll>
    #define f(i,j,k) f[i][j][k+105]
    const ll inf=1e18;
    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;
    }
    struct Line{int u,v,w,k;}e[MAX*MAX];int cnt=1;
    inline void Add(int u,int v,int w,int k){e[cnt++]=(Line){u,v,w,k};}
    int g[MAX][MAX];ll f[MAX][MAX][MAX<<1];
    vector<pi> vec[MAX],S;
    int n,m;
    int main()
    {
    	n=read();m=read();
    	for(int i=1;i<=m;++i)
    	{
    		int u=read(),v=read(),w=read(),k=read();
    		Add(u,v,w,k);g[u][v]=1;
    	}
    	for(int i=1;i<=n;++i)g[i][i]=1;
    	for(int k=1;k<=n;++k)
    		for(int i=1;i<=n;++i)
    			for(int j=1;j<=n;++j)
    				g[i][j]|=g[i][k]&g[k][j];
    	for(int i=0;i<=n;++i)
    		for(int j=1;j<=n;++j)
    			for(int k=-n;k<=n;++k)
    				f(i,j,k)=inf;
    	f(0,1,0)=0;
    	for(int i=1;i<=n;++i)
    	{
            memcpy(f[i],f[i-1],sizeof(f[i]));
    		for(int j=1;j<=m;++j)
    		{
    			int u=e[j].u,v=e[j].v,w=e[j].w,s=e[j].k;
    			for(int k=-n;k<=n;++k)
    				if(f(i-1,u,k)<inf)
    					f(i,v,k+s)=min(f(i,v,k+s),f(i-1,u,k)+w);
    		}
    	}
    	for(int i=1;i<=n;++i)
    		for(int k=-n;k<=n;++k)
    			if(f(n,i,k)!=inf)
    			{
    				ll l=-inf,r=inf;bool fl=false;
    				for(int j=-n;j<=n;++j)
    					if(f(n-1,i,j)!=inf)
    					{
    						if(k>j)r=min(r,(ll)ceil(1.0*(f(n-1,i,j)-f(n,i,k))/(k-j)));
    						else if(k<j)l=max(l,(ll)floor(1.0*(f(n-1,i,j)-f(n,i,k))/(k-j)));
    						else if(f(n,i,k)>=f(n-1,i,j)){fl=true;break;}
    					}
    				if(!fl&&l<r)vec[i].push_back(make_pair(l,r));
    			}
    	for(int i=1;i<=n;++i)
    	{
    		S.clear();
    		for(int j=1;j<=n;++j)
    			if(g[1][j]&&g[j][i])
    				for(auto p:vec[j])S.push_back(p);
    		sort(S.begin(),S.end());
    		ll l=inf,r=-inf,lst=-inf;
    		bool fl=false;
    		for(int j=0,len=S.size();j<len;++j)
    		{
    			if(!j&&S[j].first>-inf)
    			{
    				l=-inf;r=S[j].first;
    				fl=true;break;
    			}
    			if(lst!=-inf&&lst<=S[j].first)
    			{
    				l=lst;r=S[j].first;
    				fl=true;break;
    			}
    			lst=max(lst,S[j].second);
    		}
    		if(!fl&&lst<inf)l=lst,r=inf;
    		if(l==-inf||r==inf||!S.size())puts("-1");
    		else printf("%lld
    ",max(0ll,r-l+1));
    	}
    	return 0;
    }
    
  • 相关阅读:
    容器占用空间的小问题
    一个ipv4到ipv6的移植问题
    一个linux内核模块移植到低版本时发生的异常
    一个发包乱序问题记录
    一个docker镜像中的目录删除不了问题
    C/C++(共用体与枚举)
    C/C++(数据结构栈的实现)
    C/C++(结构体)
    C/C++(内存管理)
    C/C++(指针数组)
  • 原文地址:https://www.cnblogs.com/cjyyb/p/11047191.html
Copyright © 2011-2022 走看看