大意:
给你一张无向图,边有种类。
当你第一次/重新进入某种边时费用 + 1
在同一种边之间行走无费用。
求 1 到 n 的最小费用。
嗯...乍一看有一个很直观的想法:记录每个点的最短路的上一条边的种类。
但是这个算法是个错的......有些数据能够hack掉。
由于边权只有0 & 1,考虑01BFS。
事实上我们还要记录每个点来之前的边,然后就要写结构体/pair
然后还要判重...
正解:考虑按照每个点的边的type拆点。
在不同点的同一type分点之间边权为0
原点与拆出来的点之间边权为1
然后跑01BFS即可。
开n个map来存点的分点编号。
map 的 count 用法(虽然没啥卵用)
我照着正解写了个过了,然后写了自己的想法就WA.....
不知道为什么。对拍可能生成的数据太弱了,全是符合的。
1 #include <cstdio> 2 #include <map> 3 #include <deque> 4 5 const int N = 1000010; 6 7 int cnt; 8 9 std::map<int, int> mp[N]; 10 11 struct Edge { 12 int v, nex, len; 13 }edge[N << 2]; int top; 14 15 int e[N], dis[N], vis[N]; 16 17 inline int get(int x, int type, int &f) { 18 if(mp[x][type]) { 19 f = 0; 20 return mp[x][type]; 21 } 22 f = 1; 23 return mp[x][type] = ++cnt; 24 } 25 26 inline void add(int x, int y, int z) { 27 ++top; 28 edge[top].v = y; 29 edge[top].len = z; 30 edge[top].nex = e[x]; 31 e[x] = top++; 32 edge[top].v = x; 33 edge[top].len = z; 34 edge[top].nex = e[y]; 35 e[y] = top; 36 return; 37 } 38 39 inline int BFS(int s, int t) { 40 vis[s] = 1; 41 dis[s] = 0; 42 std::deque<int> Q; 43 Q.push_back(s); 44 while(!Q.empty()) { 45 int x = Q.front(); 46 Q.pop_front(); 47 for(int i = e[x]; i; i = edge[i].nex) { 48 int y = edge[i].v; 49 if(vis[y]) { 50 continue; 51 } 52 dis[y] = dis[x] + edge[i].len; 53 if(y == t) { /// error : y == s 54 return dis[y]; 55 } 56 vis[y] = 1; 57 if(edge[i].len) { 58 Q.push_back(y); 59 } 60 else { 61 Q.push_front(y); 62 } 63 } 64 } 65 return -1; 66 } 67 68 int main() { 69 freopen("in.in", "r", stdin); 70 freopen("my.out", "w", stdout); 71 int n, m; 72 scanf("%d%d", &n, &m); 73 cnt = n; 74 for(int i = 1, x, y, z, f; i <= m; i++) { 75 scanf("%d%d%d", &x, &y, &z); 76 int x_type = get(x, z, f); 77 if(f) { 78 add(x, x_type, 1); 79 } 80 int y_type = get(y, z, f); 81 if(f) { 82 add(y, y_type, 1); 83 } 84 add(x_type, y_type, 0); 85 } 86 87 int ans = BFS(1, n); 88 printf("%d", ans >> 1); 89 90 return 0; 91 }