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

来源:互联网 发布:中欧工程技术学院知乎 编辑:程序博客网 时间:2024/06/05 11:15



题意:

有一张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 longtypedef 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;}

原创粉丝点击