标签:
题意:给出n个点,m条边的无向图,每条边有一种颜色,求从结点1到结点n颜色字典序最小的最短路径。
析:首先这是一个最短路径问题,应该是BFS,因为要保证是路径最短,还要考虑字典序,感觉挺麻烦的,并不好做,事实用两次BFS,
第一次是倒序BFS,目的是得到从结点 i 到结点n的最短距离,然后再从第一个点开始到最后一个,要保证在查找时,每经过一点要让d值恰好减少1,
直到终点,这也是一个BFS,因为这个字典序在某个结点是一样的,所以是两个BFS,我超时了好几次,因为少写了一个vis, 一定要细心,
据说可以只用一次BFS,倒序,如果有兴趣可以尝试,反正我暂时没想出来,毕竟倒着字典序不好找.
再就是这个图不好构造,不能用二维数组,我用一个vector来存在,用了2*n个长度,偶数下标存结点,奇数存颜色,遍历时要注意是+2, 不是++.
代码如下:
#include <iostream> #include <cstdio> #include <algorithm> #include <vector> #include <queue> #include <cstring> using namespace std; const int maxn = 200000 + 5; const int INF = 0x3f3f3f3f; int d[maxn], vis[maxn], ans[maxn]; vector<int> v[maxn]; int Min(int a, int b){ return a < b ? a : b; } void bfs1(int n){//逆序BFS memset(d, 0, sizeof(d)); queue<int> q; memset(vis, 0, sizeof(vis)); q.push(n); vis[n] = 1; while(!q.empty()){ int u = q.front(); q.pop(); for(int i = 0; i < v[u].size(); i += 2){ int t = v[u][i]; if(t == 1){ d[1] = d[u] + 1; return; }//小优化,找到1就行了 if(vis[t])continue; d[t] = d[u] + 1; vis[t] = 1; q.push(t); } } } void bfs2(int n){ memset(vis, 0, sizeof(vis)); queue<int> q; q.push(n); vis[n] = 1; fill(ans, ans+d[1]+1, INF); while(!q.empty()){ int u = q.front(); q.pop(); if(!d[u]) return ; int m = INF; for(int i = 1; i < v[u].size(); i += 2) if(d[u] == d[v[u][i-1]]+1) m = Min(m, v[u][i]); ans[d[1]-d[u]] = Min(ans[d[1]-d[u]], m); for(int i = 0; i < v[u].size(); i += 2) if(!vis[v[u][i]] && d[u] == d[v[u][i]]+1 && v[u][i+1] == m){ vis[v[u][i]] = 1; q.push(v[u][i]); } } } int main(){ // freopen("in.txt", "r", stdin); int n, m; while(scanf("%d %d", &n, &m) == 2){ for(int i = 1; i <= n; ++i) v[i].clear(); int x, y, w; for(int i = 0; i < m; ++i){ scanf("%d %d %d", &x, &y, &w); v[x].push_back(y); v[x].push_back(w); v[y].push_back(x); v[y].push_back(w); } bfs1(n); bfs2(1); printf("%d\n", d[1]); for(int i = 0; i < d[1]; ++i) if(!i) printf("%d", ans[i]); else printf(" %d", ans[i]); printf("\n"); } return 0; }
标签:
原文地址:http://www.cnblogs.com/dwtfukgv/p/5595471.html