uva 1599

来源:互联网 发布:win10网络授权 编辑:程序博客网 时间:2024/06/05 00:24

原题
最近课业比较繁忙, 好久没时间写题了。
这也算是最短路径问题的改版,求满足一个条件的最短路径。
经验不足,一开始自然就想到用DFS(因为比较好写),结果当然TLE了
后来才想起来DFS的复杂度是O(N^2), 而BFS是O(N+E),
所以遇到这种规模比较大的图肯定要用BFS了, 根本不是一个数量级啊
网上虽然方法比较多, 但是描述得不是很全面, 我再来整理一下吧
主要思路是用两次BFS, 比较巧妙
第一次逆向BFS(从终点出发)找出终点到所有点的距离并标记, 比较简单就不赘述了
第二次BFS是关键, 从起点出发, 首先要知道下一次走的点应该是那些与终点距离只比起点少1的点, 只有这样才能保证走的都是最短路径.
每到一个点, 关键就是用一个点集nextVertices来存储下一步能走的所有点之中边权最小的点(而不是单独的一个变量表示当前的点, 就相当于多路同步进行),
我是先遍历一边所有可能走的边找出最小边权MinColor, 然后再遍历以便找出边权等于MinColor的点, 就放进下一轮要选择走的点集nextVertices内
这里需要注意的一个小细节, 刚要开始第二次BFS的时候, 只把起点放入nextVertices就能开始上述循环了

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <algorithm>#include <string>#include <vector>#include <set>#include <stack>#include <queue>#include <deque>#include <map>#include <list>#include <cassert>#include <iomanip>using namespace std;const int MAXN = 200000+1;      const int INF  = 1000000000 + 10;typedef long long LL;/*uva 1599关键 :    0.  用BFS而不用DFS的原因是在结点较多的情况下BFS(O(V+E))更快         1.  第一次倒着BFS找到终点到其余各点的最短路径长度,             [关键难点]第二次正向BFS从中找到到达终点的最短路径        2.  第二次如果有color值相同的边如何确定下一个点?        解决方法 : 先从与当前点邻接的边中找出所有边最小的color值 min_color,                之后再遍历容器内的边, 找出color值等于min_color的所有边,                保存这些边指向的顶点, 这些顶点即为下一轮需要BFS的顶点 */map<int, map<int,int> > G;          // 无向网图 int M, N;bool isVisited[MAXN];int  Distance[MAXN];                // 记录各个点到终点的距离 typedef map<int,int>::iterator MPIT;//bool Lessthan(int * path1, int * path2){    while( *path1++ == *path2++ );    return *path1 < *path2;}void BFS_first(){    queue<int> Q;    Q.push(N);    int dis = 0;    Distance[N] = 0;    while( !Q.empty() ){        int cur = Q.front(); Q.pop();        MPIT it = G[cur].begin();        while( it!=G[cur].end() ){            if( !Distance[it->first] && it->first!=N ){                Distance[it->first] = Distance[cur]+1;                Q.push(it->first);            }            it++;        }    }//  for(int i=1; i<=N; i++) std::cout << Distance[i] << " " << endl;}void BFS_second(){    vector<int> ans, nextVertices;    MPIT it;    int cur;    memset(isVisited, 0, sizeof(isVisited));    nextVertices.push_back(1);    isVisited[1] = true;    for(int i=0; i<Distance[1];i++ ){        int min_color = INF;        for(int j=0; j<nextVertices.size(); j++){            cur = nextVertices[j];            it = G[cur].begin();            while( it!=G[cur].end() ){                if(Distance[cur]-1 == Distance[it->first]                    && G[cur][it->first] < min_color ){                    min_color = G[cur][it->first];                }                it++;            }        }        ans.push_back(min_color);        vector<int> tmpNext;         for(int i=0; i<nextVertices.size(); i++){            cur = nextVertices[i];            it = G[cur].begin();            while( it!=G[cur].end() ){                if( !isVisited[it->first] && Distance[cur]-1 == Distance[it->first]                    && G[cur][it->first] == min_color ){                    isVisited[it->first] = true;                    min_color = G[cur][it->first];                    tmpNext.push_back(it->first);                }                it++;            }        }        nextVertices = tmpNext;    }    cout << ans.size() << endl;    for(int i=0; i<ans.size()-1; i++) cout << ans[i] << " ";    cout << ans[ans.size()-1] << endl;}int main(){//  freopen("input2.txt","r",stdin);    while( cin >> N >> M ){        int a, b, c;        G.clear();        memset(Distance, 0, sizeof(Distance));        for(int i=0; i<M; i++){            cin >> a >> b >> c;            if( G[a][b]==0 || c < G[a][b] ){ // 当没有加过边或者准备要加的边更短就更新边                 G[a][b] = G[b][a] = c;                          }        }        BFS_first();         BFS_second();    }    return 0;}
0 0
原创粉丝点击