1. 程式人生 > 其它 >P2149 [SDOI2009]Elaxia的路線 題解

P2149 [SDOI2009]Elaxia的路線 題解

Elaxia的路線

求兩對點間的最短路的最長公共路徑。

思路

記錄哪些邊在公共的最短路徑上。做法:跑四遍最短路,判斷是否同時滿足兩個點對disfromS[u]+w[i]+disfromT[v]==disfromS[T]。摳出公共路徑(有向的,最短路求後),在公共路徑組成的新圖上考慮最長路徑。轉化為套路性問題求最大鏈長,拓撲排序DP即可。
dijstera更快。

程式碼

int n,m,id;
int s1,t1,s2,t2;
int h[N],e[M],ne[M],w[M],idx;
int h1[N],e1[M],ne1[M],w1[M],idx1;
int dis[4][N];
int din[N],f[N];
bool vis[N];
inline void add(int a,int b,int c)
{...}

inline void add1(int a,int b,int c)
{...}

inline void spfa(int rt)
{...}

inline void new_graph()
{
	for(int u = 1;u <= n;u++)
	   for(int i = h[u];~i;i = ne[i]){
	   	int j = e[i];
	   	if((dis[0][u] + w[i] + dis[1][j] == dis[0][t1])){//注意判斷第二個正反兩向邊,第一個必然正反都被遍歷
	   		if(dis[2][u] + w[i] + dis[3][j] == dis[2][t2]) add1(u,j,w[i]);
	   		if(dis[2][j] + w[i] + dis[3][u] == dis[2][t2]) add1(j,u,w[i]);
		   } 
	   }
}

inline void topsort()
{
	queue<int> q;
	memset(f,-INF,sizeof f);
	for(int i = 1;i <= n;i++){
	   if(!din[i]){
	   	f[i] = 0;
	   	q.push(i);
	   }
	}
	while(q.size())
	{
		int u = q.front();
		q.pop();
		for(int i = h1[u];~i;i = ne1[i]){
			int j = e1[i];din[j]--;
			if(f[j] < f[u] + w1[i]) f[j] = f[u] + w1[i];
			if(!din[j]) q.push(j);
		}
	}
}

signed main()
{
	id = 1;spfa(s1);
	id = 2;spfa(t1);
	id = 3;spfa(s2);
	id = 4;spfa(t2);
	new_graph();
	topsort();
	int mx = -1;
	for(int i = 1;i <= n;i++) mx = max(mx,f[i]);
	printf("%d\n",mx);
	return 0;
}
艱難困苦,玉汝於成