#倍增优化Floyd# [luogu CF148E] Porcelain

Title

CF147B Smile House


Solution

d [ s ] [ i ] [ j ] d[s][i][j] d[s][i][j] d d d步从 i i i j j j的距离, d [ s ] [ i ] [ j ] = m a x ( d [ s ] [ i ] [ j ] , d [ s − 1 ] [ i ] [ k ] + d [ 1 ] [ k ] [ j ] ) d[s][i][j]=max(d[s][i][j],d[s-1][i][k]+d[1][k][j]) d[s][i][j]=max(d[s][i][j],d[s1][i][k]+d[1][k][j]),若 d [ k ] [ i ] [ i ] > 0 d[k][i][i]>0 d[k][i][i]>0 k k k是答案。 这是 O ( n 4 ) O(n^4) O(n4),能拿70分。
我们可以用倍增优化成 O ( n 3 l o g n ) O(n^3logn) O(n3logn)
d [ s ] [ i ] [ j ] d[s][i][j] d[s][i][j]为不超过 2 s 2^s 2s步从 i i i j j j的距离, d [ s ] [ i ] [ j ] = m a x ( d [ s ] [ i ] [ j ] , d [ s − 1 ] [ i ] [ k ] + d [ s − 1 ] [ k ] [ j ] ) d[s][i][j]=max(d[s][i][j],d[s-1][i][k]+d[s-1][k][j]) d[s][i][j]=max(d[s][i][j],d[s1][i][k]+d[s1][k][j])
像倍增求 l c a lca lca一样,从大到小枚举 s s s
如果当前存在正环,就继续枚举更小的可行解,否则累加 2 s − 1 2^{s-1} 2s1,这种情况下需要保留上一次的最长路径。
对于答案需要++,因为自己这个点没有累加。


Code

#include
#include
#include
#define rep(i,x,y) for(register int i=x;i<=y;i++)
using namespace std; 
const int N=305; 
const int M=10; 
int n,m,d[M+5][N][N],q[N][N],t[N][N],ans; 
int main(){
	memset(d,0xcf,sizeof(d)); 
	memset(q,0xcf,sizeof(q)); 
	scanf("%d%d",&n,&m); 
	rep(i,1,m){
		int x,y,z,zz; 
		scanf("%d%d%d%d",&x,&y,&z,&zz); 
		d[0][x][y]=z; d[0][y][x]=zz; 
	}
	rep(i,1,n) d[0][i][i]=q[i][i]=0; 
	rep(s,1,M) rep(k,1,n) rep(i,1,n) rep(j,1,n) d[s][i][j]=max(d[s][i][j],d[s-1][i][k]+d[s-1][k][j]); 
	for(int s=M;s>=0;s--){
		memset(t,0xcf,sizeof(t)); bool b=0; 
		rep(k,1,n) rep(i,1,n) rep(j,1,n) t[i][j]=max(t[i][j],q[i][k]+d[s][k][j]); 
		rep(i,1,n) if (t[i][i]>0) {b=1; break;}
		if (b) continue; else {
			rep(i,1,n) rep(j,1,n) q[i][j]=t[i][j]; 
			ans+=(1<<s); 
		}
	}
	printf("%d",ans>=n?0:ans+1); 
	return 0; 
}

你可能感兴趣的:(倍增(RMQ/st算法,树上倍增),最短路径,倍增优化,floyd,luogu,cf148e,pporcelain)