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;
}
艰难困苦,玉汝于成

浙公网安备 33010602011771号