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; }
相关文章推荐
- HDU 6166 Senior Pan(多校第九场 二进制分组最短路)
- HDU 6170 && 2017 多校训练:Two strings(DP)
- HDU 6166 Senior Pan(思维 最短路)
- Hdu 6166 Senior Pan【思维+随机化+最短路】好题~
- 2017 第十场多校训练 HDU 6181 Two Paths 次短路+Dijkstra
- HDU 6134 && 2017 多校训练:Battlestation Operational(莫比乌斯反演+积性函数)
- HDU 6166 Senior Pan (多源多汇最短路+集合的二进制划分 17多校第九场第6题)
- HDU 6162 && 2017 多校训练:Ch's gift(树链剖分)
- Senior Pan HDU - 6166 (最短路咯)
- (2017多校训练第二场)HDU - 6055 & POJ - 2002 Regular polygon 哈希
- HDU 6178 && 2017 多校训练:Monkeys(DFS)
- hdu 6166 Senior Pan(多源多汇最短路)
- HDU 6180 && 2017 多校训练:Schedule
- 2017 Multi-University Training Contest 9 && HDU 6166 Senior Pan 【最短路+思维】
- hdu 6166 Senior Pan(多源最短路径)(二进制划分集合)
- hdu 6166 Senior Pan(巧妙的Dijkstra)
- (2017多校训练第三场)HDU - 6058 Kanade's sum 链表
- 2017 多校训练第二场 HDU 6045 Is Derek lying?(思维)
- HDU-2017 多校训练赛10-1011-Two Paths
- 【(好题)组合数+Lucas定理+公式递推(lowbit+滚动数组)+打表找规律】2017多校训练七 HDU 6129 Just do it