题解 P2149 【[SDOI2009]Elaxia的路线】
蒟蒻的第一道紫题题解……最慢的做法(300+ms)
思路:首先跑四遍Dijkstra,选出所有满足dists1[a]+distt1[a]==dists1[t1] && dists2[a]+distt2[a]==dists2[t2]的点,即在双方最短路上都有的点。
可以看到,这些点构成了一些子图,这些子图的直径就是所求的长度。证明不会证。
求直径的方法就是随便选一个点,跑一遍Dijkstra,找到最远的那个点,再跑一遍Dijkstra,找到最远的距离,就是直径。(不会证)
时间复杂度:
优化一下(在Dijkstra里面直接用队列记录访问过的点)可以做到
用了一点函数指针知识以简化代码。
#include <queue>
#include <cstdio>
using namespace std;
void chkmax(int& a,int b)
{
if(b>a)
{
a = b;
}
}
int beg[1505];
int ed[450005];
int nxt[450005];
int len[450005];
int top;
void addedge(int a,int b,int l)
{
++top;
len[top] = l;
nxt[top] = beg[a];
beg[a] = top;
ed[top] = b;
}
int n;
int vis[1505];
void fillter_dijkstra(int* dist,int s,bool (*fillter)(int)) //fillter是个函数指针
{
for(int i=1; i<=n; ++i)
{
dist[i] = 0x7f7f7f7f;
vis[i] = 0;
}
dist[s] = 0;
priority_queue<pair<int,int> > pq;
pq.push(make_pair(0,s));
while(!pq.empty())
{
int th = pq.top().second;
pq.pop();
while(vis[th])
{
if(pq.empty()) break;
th = pq.top().second;
pq.pop();
}
vis[th] = 1;
for(int p=beg[th]; p; p=nxt[p])
{
if(fillter(ed[p]) && dist[th]+len[p] < dist[ed[p]])
{
dist[ed[p]] = dist[th]+len[p];
pq.push(make_pair(-dist[ed[p]],ed[p]));
}
}
}
}
bool always(int x)
{
return true;
}
void dijkstra(int* dist,int s)
{
fillter_dijkstra(dist,s,always);
}
int s1,t1,s2,t2;
int dists1[1505];
int dists2[1505];
int distt1[1505];
int distt2[1505];
bool can(int a)
{
return dists1[a]+distt1[a]==dists1[t1] && dists2[a]+distt2[a]==dists2[t2];
}
int caned[1505];
int disttmp[1505];
int main()
{
int m;
scanf("%d%d%d%d%d%d",&n,&m,&s1,&t1,&s2,&t2);
for(int i=1; i<=m; ++i)
{
int a,b,l;
scanf("%d%d%d",&a,&b,&l);
addedge(a,b,l);
addedge(b,a,l);
}
dijkstra(dists1,s1);
dijkstra(dists2,s2);
dijkstra(distt1,t1);
dijkstra(distt2,t2);
int ans = 0;
for(int i=1; i<=n; ++i)
{
if(!caned[i] && can(i))
{
fillter_dijkstra(disttmp,i,can);
int maxpos = i;
for(int j=1; j<=n; ++j)
{
if(vis[j])
{
caned[j] = 1;
if(disttmp[j] > disttmp[maxpos])
{
maxpos = j;
}
}
}
fillter_dijkstra(disttmp,maxpos,can);
for(int j=1; j<=n; ++j)
{
if(vis[j])
{
chkmax(ans,disttmp[j]);
}
}
}
}
printf("%d\n",ans);
}