题意及思路:https://blog.csdn.net/yzyyylx/article/details/90145400
这题主要巧妙在分析了最短路算法的性质,得出大小小于等于3的连通块一定不会被再次访问的结论。
代码:
#include <bits/stdc++.h> using namespace std; bool v[80][1 << 18]; int dp[80][1 << 18]; const int maxn = 1010; struct node { int dis, state, now; bool operator < (const node& rhs) const { return dis > rhs.dis; } }; struct Edge { int v, w; }; vector<Edge> G[maxn]; int sz[maxn], num[maxn], ans[maxn]; int A, B, n, m, tot; void add(int x, int y, int z) { G[x].push_back((Edge){y, z}); G[y].push_back((Edge){x, z}); } priority_queue<node> q; int f[maxn]; int get(int x) { if(x == f[x]) return x; return f[x] = get(f[x]); } void merge(int x, int y) { int x1 = get(x), y1 = get(y); if(x1 == y1) return; f[x1] = y1; sz[y1] += sz[x1]; } int get_num(int x) { if(sz[get(x)] > 3) return 1 << num[get(x)]; else return 0; } void dijkstra() { memset(dp, 0x3f, sizeof(dp)); memset(ans, 0x3f, sizeof(ans)); q.push((node){0, get_num(1), 1}); dp[1][get_num(1)] = 0; while(!q.empty()) { node tmp = q.top(); q.pop(); if(v[tmp.now][tmp.state]) continue; v[tmp.now][tmp.state] = 1; ans[tmp.now] = min(ans[tmp.now], tmp.dis); for (auto x : G[tmp.now]) { if(x.w == B && get(x.v) == get(tmp.now)) continue; if(x.w == B && (tmp.state & get_num(x.v))!= 0) continue; if(x.w + tmp.dis < dp[x.v][get_num(x.v) | tmp.state]) { dp[x.v][get_num(x.v) | tmp.state] = x.w + tmp.dis; q.push((node){dp[x.v][get_num(x.v) | tmp.state], get_num(x.v) | tmp.state, x.v}); } } } } int main() { int x, y, z; scanf("%d%d%d%d", &n, &m, &A, &B); for (int i = 1; i <= n; i++) { f[i] = i; sz[i] = 1; } for (int i = 1; i <= m; i++) { scanf("%d%d%d", &x, &y, &z); add(x, y, z); if(z == A) { merge(x, y); } } for (int i = 1; i <= n; i++) { if(i == get(i) && sz[i] > 3) { num[i] = tot++; } } dijkstra(); for (int i = 1; i <= n; i++) printf("%d ", ans[i]); }