例题6-20 理想路径 UVa1599

来源:互联网 发布:美国有矩阵风投公司吗 编辑:程序博客网 时间:2024/04/30 21:22

1.题目描述:点击打开链接

2.解题思路:本题要求寻找一条从1到n的路径,使得经过的边数最少,若边数相同时,输出颜色值字典序最小的那条路径。路径问题用BFS解决,但本题需要用两次BFS,第一次来统计所有点到n的路径长度;第二次从1出发,沿着路径长度恰好每次减一的点逐步走到终点,但由于从u到v满足d[u]-d[v]==1的路径有多条,需要扫描所有这些路径,找颜色值最小的那条,这就是第二次BFS的目的所在。这里用到一个小技巧:因为队列中的边都是满足d[u]-d[v]==1的,因此d[1]-d[v]必然是一个不小于0的定值,因此可用path[d[1]-d[v]]来记录最小的颜色值。这道题我以前尝试独立敲代码但没做出来,现在找到了一份很好的代码,值得学习。

3.代码:

#define _CRT_SECURE_NO_WARNINGS #include<iostream>#include<algorithm>#include<string>#include<sstream>#include<set>#include<vector>#include<stack>#include<map>#include<queue>#include<deque>#include<cstdlib>#include<cstdio>#include<cstring>#include<cmath>#include<ctime>#include<functional>using namespace std;#define MAXN 100000struct node{int v, c;//v代表边edge[u]的另一端,c代表该边的颜色node *next;}edge[MAXN * 4 + 10];node *adj[MAXN + 10];node *ecnt = edge;//ecnt是当前边列表的末尾inline void addedge(const int &u, const int &v, const int &c){node *p = ++ecnt;p->v = v;p->c = c;p->next = adj[u];//adj[u]是所有以u为起点的边的链表adj[u] = p;}int d[MAXN + 10], path[MAXN + 10];bool vis[MAXN + 10];queue<int>q;int n, m;void bfs1(int s){memset(d, 0, sizeof(d));d[s] = 1;//终点长度为1q.push(s);while (!q.empty()){int u = q.front();//刚开始时u是终点nq.pop();for (node *p = adj[u]; p; p = p->next)//扫描终点n连接的所有边{int v = p->v;if (!d[v]){d[v] = d[u] + 1;q.push(v);}}}}queue<pair<int, int> >q2;void bfs2(int s){memset(path, 0x3f, sizeof(path));memset(vis, 0, sizeof(vis));q2.push(make_pair(s, 0));path[0] = 0;while (!q2.empty()){int u = q2.front().first;int cy = q2.front().second;q2.pop();if (path[d[1] - d[u]] != cy || vis[u]) continue;vis[u] = true;//访问过结点ufor (node *p = adj[u]; p; p = p->next)//扫描所有从u出发的边,找颜色值最小的边{int v = p->v;int c = p->c;if (d[u] != d[v] + 1 || path[d[1] - d[v]] <= c) continue;//如果从u到v的距离不是恰好减少1 或者 虽满足条件1但颜色值大于目前的最小值,忽略path[d[1] - d[v]] = c;//标记结点1到v的颜色最小值}for (node *p = adj[u]; p; p = p->next){int v = p->v;int c = p->c;if (d[u] != d[v] + 1 || path[d[1] - d[v]] != c) continue;//如果满足u到v距离恰好减少1且颜色值最小q2.push(make_pair(v, c));//将满足条件的路径入列}}d[1]--;//由于bfs1中定义了d[n]=1,因此这里要减去1int i;printf("%d\n", d[1]);for (i = 1; i<=d[1]; i++)printf("%d%c", path[i],i==d[1]?'\n':' ');}int main(){int u, v, w, i;while (scanf("%d%d", &n, &m) == 2){memset(adj, 0, sizeof(adj));ecnt = edge;for (i = 1; i <= m; i++){scanf("%d%d%d", &u, &v, &w);addedge(u, v, w);//u为起点addedge(v, u, w);//v为起点}bfs1(n);//从终点n开始逆向bfs,统计所有点到终点的最短距离bfs2(1);//从起点开始正向bfs,找颜色序列字典序最小的路径}return 0;}


1 0