「2017 山东一轮集训 Day6」重建 - dp

题目大意:
给一张无向带权连通图,和一些关键点,求一个最大的非负整数c,使得每条边的边权加上c之后,s到t的最短路等于s到t只经过关键点的最短路。
题解:观察到s到t的最短路是一个关于边数的分段函数,令f[x,i]表示从s出发走到x经过恰好i条边的最短路,g为经过关键点的数组。
那么分别意会出这两个分段函数后,就是求一个x,使得两个函数在此处取值相同。
注意到g[t,i]>=f[t,i],也就是当有某个位置x成为答案时,一定有某个i,设第i段的有效范围的交集是[L,R],则 x [ L , R ] x\in[L,R] ,并且此时g[t,i]=f[t,i]。
那么枚举这样的i,计算相应的R,然后对所有的R取个max即可。

#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define db double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
	int x,ch;while((ch=gc)<'0'||ch>'9');
	x=ch^'0';while((ch=gc)>='0'&&ch<='9')
		x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=1010,M=10010;
const lint INF=LLONG_MAX/10;
struct edges{
	int to,pre,wgt;
}e[M<<1];int h[N],etop;
lint f[N][M],g[N][M];int imp[N];
inline int add_edge(int u,int v,int w) { return e[++etop].to=v,e[etop].wgt=w,e[etop].pre=h[u],h[u]=etop; }
inline int getdis(lint (*f)[M],int n,int s)
{
	rep(i,1,n) rep(j,0,n) f[i][j]=INF;f[s][0]=0;
	rep(i,1,n) rep(x,1,n) if(imp[x]) for(int t=h[x],y;t;t=e[t].pre)
		if(imp[y=e[t].to]) f[x][i]=min(f[x][i],f[y][i-1]+e[t].wgt);
	return 0;
}
inline lint getinter(lint *f,int a,int b,int sqz)
{
	if(a>b) swap(a,b);
	if(f[a]<f[b]) return -1;
	if(f[a]==f[b]) return 0;
	if(f[a]==INF) return INF;
	lint x=f[a]-f[b],y=b-a;
	if(sqz) return (x-1)/y+1;
	return x/y;
}
inline int getrange(lint *f,int m,int p,lint &L,lint &R)
{
	L=-1,R=INF;
	rep(i,1,p-1) R=min(R,getinter(f,p,i,0));//xiaquzheng
	rep(i,p+1,m) L=max(L,getinter(f,p,i,1));//shangquzheng
	return 0;
}
int main()
{
	for(int T=inn();T;T--)
	{
		int n=inn(),m=inn(),s=inn(),t=inn();lint ans=-1;
		memset(h,0,sizeof(int)*(n+1)),etop=0;int x,y,w;
		rep(i,1,m) x=inn(),y=inn(),w=inn(),add_edge(x,y,w),add_edge(y,x,w);
		rep(i,1,n) imp[i]=1;getdis(f,n,s);
		rep(i,1,n) imp[i]=0;int k=inn();
		rep(i,1,k) imp[inn()]=1;getdis(g,n,s);
		rep(i,0,n) if(f[t][i]==g[t][i]&&f[t][i]<INF)
		{
			lint l,r;getrange(f[t],n,i,l,r);
			lint L,R;getrange(g[t],n,i,L,R);
			L=max(L,l),R=min(R,r);
			if(L<=R) ans=max(ans,R);
			if(ans==INF) break;
		}
		if(ans<0) printf("Impossible\n");
		else if(ans==INF) printf("Infinity\n");
		else printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/84916140