• Codeforces Gym100783H 最短路 其他


    原文链接https://www.cnblogs.com/zhouzhendong/p/CF-Gym100783H.html

    题目传送门 - CF-Gym100783H

    题意

      给定一个 $n$ 个节点 $P$ 条带权边的无向图,有 $m$ 个特殊点。给定开始点 $X$ 和结束点 $Y$ 。

      现在请你求一个 $k$ ,使得令所有边的权值都加上 $k$ 之后,$X$~$Y$ 的最短路经过且仅经过特殊点,不能有其他的最短路途中任意一个节点不是特殊点。

      问满足条件的 $k$ 最大是多少。如果 $k=infty$ ,则输出 $Infinity$ 。如果不存在这样的 $k$ 则输出 $Impossible$ 。否则输出 $k$ 的值。

      $n,mleq 1000, Pleq 10000, 1leq X,Yleq n$

    题解

      我们记原图为 $g1$,记仅包含特殊点和连接他们的边的图为 $g2$ 。

      对于 $g1$ 和 $g2$ 我们分别求出 $X$ 走 $i$ 步到 $Y$ 的最短路(按照原来的边权)。这个可以 nm simple dp 。

      我们记 $g1$ 和 $g2$ 中最多走 $i$ 步从 $S$ 到 $T$ 的最短路值分别为 $v1[i]$ 和 $v2[i]$ 。

      然后我们枚举一个 $i$ 并求走最多 $i$ 步到达 $T$ 在 $g_1$ 中的最短路值为全局最短路的 $k$ 的取值范围。

      这个取值范围如何求?

      我们得满足走 $i$ 步是最短的。所以:

      对于 $j=i$ : $v1[i]=v2[j]$

      对于 $j>i$ : $v1[i]+kileq v1[j]+kjLongrightarrow v1[i]-v1[j]leq k(j-i)Longrightarrow kgeq cfrac{v1[i]-v1[j]}{j-i}$

      对于 $j<i$ : $v1[i]+kileq v1[j]+kjLongrightarrow v1[j]-v1[i]geq k(i-j)Longrightarrow kleq cfrac{v1[j]-v1[i]}{i-j}$

      如果满足上述条件的 $k$ 存在,那么我们可以用满足上述条件的最大 $k$ 值来更新答案。

      细心的你可能已经发现了,我这个做法忽略了可能存在的经过非特殊点的最短路的情况。

      要搞定这个东西其实很简单。我们取一个略大于 $n$ 的值 : $1024$,对于每一个初始边权 $v$,如果它连接的是两个特殊点,那么令 $v^prime =1024v$ 否则 $v^prime = 1024v+1$ 。

      这样有什么用呢?如果存在走 $j$ 步且经过非特殊点的最短路,那么 $dis mod 1024 < j$ 。

      这个相等权值的情况要特别注意。别忘了在求之前 $k$ 的取值范围中也要加上关于这个的特判,微调一下 $k$ 的取值范围。

      建议提前判掉 $Infinity$ 的情况和部分 $Impossible$ 的情况。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=1005;
    const LL INF=1LL<<62;
    int n,m,S,T;
    int owned[N];
    struct Gragh{
    	static const int M=20005;
    	int cnt,x[M],y[M],nxt[M],fst[N];
    	LL z[M];
    	void clear(){
    		cnt=0;
    		memset(fst,0,sizeof fst);
    	}
    	void add(int a,int b,int c){
    		y[++cnt]=b,x[cnt]=a,z[cnt]=c,nxt[cnt]=fst[a],fst[a]=cnt;
    	}
    }g,g2;
    void Get_owned(){
    	memset(owned,0,sizeof owned);
    	int m,x;
    	scanf("%d",&m);
    	while (m--)
    		scanf("%d",&x),owned[x]=1;
    }
    LL v1[N],v2[N];
    LL dis[N][N];
    void Getv(Gragh &g,LL v[]){
    	for (int i=0;i<n;i++)
    		for (int j=1;j<=n;j++)
    			dis[i][j]=INF;
    	dis[0][S]=0;
    	for (int i=0;i<n-1;i++)
    		for (int j=1;j<=g.cnt;j++)
    			dis[i+1][g.y[j]]=min(dis[i+1][g.y[j]],dis[i][g.x[j]]+g.z[j]);
    	for (int i=0;i<n;i++)
    		v[i]=dis[i][T];
    	for (int i=1;i<n;i++)
    		v[i]=min(v[i-1],v[i]);
    }
    bool check1(){
    	return v2[n-1]<INF;
    }
    bool check2(){
    	int p1=0,p2=0;
    	while (v1[p1]==INF)
    		p1++;
    	while (v2[p2]==INF)
    		p2++;
    	return p1==p2&&v1[p1]==v2[p2];
    }
    LL k1[N],k2[N];
    LL solve3(){
    	LL ans=-1,k=0;
    	for (int i=n-1;i>0;i--){
    		if (v1[i]!=v2[i]||v2[i]==INF)
    			continue;
    		LL Min=1,Max=INF;
    		// v1[i]+k*i <= v1[j]+k*j
    		// v1[i]-v1[j] <= k*(j-i)
    		// k >= (v1[i]-v1[j]) / (j-i)
    		for (int j=i+1;j<n;j++){
    			LL now=((v1[i]>>10)-(v1[j]>>10)+j-i-1)/(j-i);
    			if ((v1[j]&1023LL)!=j&&now*(j-i)==((v1[i]>>10)-(v1[j]>>10)))
    				now++;
    			Min=max(Min,now);
    		}
    		// v1[i]+k*i <= v1[j]+k*j
    		// k <= (v1[j]-v1[i])/ (i-j)
    		for (int j=0;j<i;j++){
    			if (v1[j]==INF)
    				continue;
    			LL now=((v1[j]>>10)-(v1[i]>>10))/(i-j);
    			if ((v1[j]&1023LL)!=j&&now*(i-j)==((v1[j]>>10)-(v1[i]>>10)))
    				now--;
    			Max=min(Max,now);
    		}
    		if (Min<=Max)
    			ans=max(ans,Max);
    	}
    	return ans;
    }
    int main(){
    while(~scanf("%d%d%d%d",&n,&m,&S,&T)){
    	g.clear(),g2.clear();
    	for (int i=1;i<=m;i++){
    		int a,b,c;
    		scanf("%d%d%d",&a,&b,&c);
    		g.add(a,b,c);
    		g.add(b,a,c);
    	}
    	Get_owned();
    	for (int i=1;i<=m*2;i++){
    		g.z[i]<<=10;
    		if (owned[g.x[i]]&&owned[g.y[i]]){
    			g.z[i]++;
    			g2.add(g.x[i],g.y[i],g.z[i]);
    		}
    	}
    	Getv(g,v1);
    	Getv(g2,v2);
    	if (!check1()){
    		puts("Impossible");
    		continue;
    	}
    	if (check2()){
    		puts("Infinity");
    		continue;
    	}
    	LL ans=solve3();
    	if (ans<0)
    		puts("Impossible");
    	else
    		printf("%lld
    ",ans);
    }
    	return 0;
    }
    

      

  • 相关阅读:
    iOS之const,static,extern简介
    ubuntu14.04安装pycurl报错: __main__.ConfigurationError: Could not run curl-config: [Errno 2] No such file or directory
    Django过滤器列表
    ubuntu 开机显示错误:无法应用原保存的显示器配置
    安装 ppsycopg2报错, Error: You need to install postgresql-server-dev-X.Y for building a server-side extension or libpq-dev for building a client-side application
    [已解决]EnvironmentError: mysql_config not found
    Ubuntu14.04安装MySQL-python异常: mysql_config: not found,Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-MJWMPd/MySQL-python/
    Ubuntu14.04通过pyenv配置多python
    【原创】No matching distribution found for Twisted>=10.0.0 (from scrapy)
    [原创] 更新Ubuntu自带的python2.X版本 ImportError: No module named pip;ImportError: No module named _sqlite3
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/CF-Gym100783H.html
Copyright © 2020-2023  润新知