您的位置:首页 > 其它

HDU 6166 && 2017 多校训练:Senior Pan(最短路)

2017-08-22 18:17 495 查看


题意:

有一张n个点m条边的有向图,还有一个包含k个点的点集,求出这个点集中任意两点间最短路的最小值

官方题解看不懂。。

如果一条边的两个端点都在这个集合中,就将这条边直接删掉(中间记录下最小值)以后不会再用

之后就可以愉快的SPFA了,len[i]表示到i点的最短路

随便设集合中的一个点x1为起点,令len[x1]=0然后求最短路,跑完之后记录所有的len[xi] (xi>1 && xi∈k)看哪个更小,之后再将集合中的第二个点x2的len[]置为0并加入队列,继续spfa,然后记录所有的len[xi] (xi>2 && xi∈k)看哪个更小,如此操作直到集合中所有点的len[]全为0

不过这样只处理了ai到aj (i<j)的最小值,所以还要初始化len[]倒过来再跑一次spfa,操作和上面一样

例如样例k=3,集合中的点为1,3,5

①删掉所有1,3,5之间的边,ans = min(ans, len(u, v))  (e(u, v)∈k)

②求出1号点到所有点的单源最短路,  然后ans = min(ans, len[3], len[5])

③令len[3]=0,将3号点加入队列继续spfa,ans = min(ans, len[5])

④没必要再加最后5号点了,初始化len数组

⑤求出5号点到所有点的单源最短路,  然后ans = min(ans, len[3], len[1])

⑥令len[3]=0,将3号点加入队列继续spfa,ans = min(ans, len[1])

结束,输出ans

看上去貌似是跑了2*k次spfa其实只跑了2次,因为你并没有清空len[]数组,所以只是相当于手动放缩了k次而已

复杂度O((n+m)log(n+m))

#include<stdio.h>
#include<vector>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define LL long long
typedef struct
{
LL v;
LL len;
}Road;
Road now;
vector<Road> G[100005];
queue<LL> q;
LL God[100005], vis[100005], sum[100005];
int main(void)
{
LL T, i, n, m, j, x, y, len, k, bet, cas = 1;
scanf("%lld", &T);
while(T--)
{
scanf("%lld%lld", &n, &m);
for(i=1;i<=n;i++)
G[i].clear();
for(i=1;i<=m;i++)
{
scanf("%lld%lld%lld", &x, &y, &len);
now.len = len, now.v = y;
G[x].push_back(now);
}
memset(God, 0, sizeof(God));
scanf("%lld", &k);
for(i=1;i<=k;i++)
{
scanf("%lld", &x);
God[x] = 1;
}
bet = 100000ll*100000+5;
for(i=1;i<=n;i++)
{
if(!God[i])  continue;
for(j=0;j<G[i].size();j++)
{
y = G[i][j].v;
if(God[y])
{
bet = min(bet, G[i][j].len);
G[i].erase(G[i].begin()+j);
j--;
}
}
}
memset(vis, 0, sizeof(vis));
memset(sum, 62, sizeof(sum));
for(i=1;i<=n;i++)
{
if(God[i])
{
vis[i] = 1;
q.push(i);
bet = min(bet, sum[i]);
sum[i] = 0;
while(q.empty()==0)
{
x = q.front();
q.pop();
vis[x] = 0;
for(j=0;j<G[x].size();j++)
{
now = G[x][j];
if(sum[x]+now.len<sum[now.v])
{
sum[now.v] = sum[x]+now.len;
if(vis[now.v]==0)
{
vis[now.v] = 1;
q.push(now.v);
}
}
}
}
}
}
memset(sum, 62, sizeof(sum));
for(i=n;i>=1;i--)
{
if(God[i])
{
vis[i] = 1;
q.push(i);
bet = min(bet, sum[i]);
sum[i] = 0;
while(q.empty()==0)
{
x = q.front();
q.pop();
vis[x] = 0;
for(j=0;j<G[x].size();j++)
{
now = G[x][j];
if(sum[x]+now.len<sum[now.v])
{
sum[now.v] = sum[x]+now.len;
if(vis[now.v]==0)
{
vis[now.v] = 1;
q.push(now.v);
}
}
}
}
}
}
printf("Case #%lld: %lld\n", cas++, bet);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: