uva UVA - 1599 Ideal Path

来源:互联网 发布:敬请悉知是什么意思 编辑:程序博客网 时间:2024/04/20 06:05

题意:给定n(<=100000)个点(1......n),m(<=200000)条边,每条边有个颜色值,试求从点1到点n经过的边数最少,在此前提下,经过的边数的颜色序列的字典树最小。

思路:如果只是边数最少直接一个bfs即可求之。现在多了个条件边数的颜色值序列的字典树最小,可以先选颜色值小的?不能,因为你不知道从颜色最小的走是否走的到,或者步数最短呢。

我们逆向思考,如果我们从终点bfs一下,记录每个点到终点的最短距离,然后我们从起点出发,每一步只往(距离-1)的节点走,因为,这样才能确保最短路径,然后,把距离相同的看作一层,从起点出发,刚开始第一次只有起点,往下一层所有节点中的最小颜色值走,没走一层确定的一个答案,如果该层最小颜色值有多个,我们不能确定到底走哪个,具体还要看下下层,因此,我们把最小颜色值所有节点看作新的一层,覆盖旧的,相当于起点从一个变成多个。这样迭代。


2.对于每个节点我们最多只放入队列一次,所以用个数组标记,不然TLE。

/*wrong:9 91 2 11 3 12 4 22 5 33 6 16 8 54 7 17 9 28 9 2*/ #include<stdio.h>#include<math.h>#include<stdlib.h>#include<algorithm>#include<string.h>#include<vector>#include<queue>using namespace std;typedef long long LL;const int maxn = 100010;int n,m;int step[2*maxn];int ans [2*maxn];int vis[2*maxn];int  T ;const int INF = 1e9+5;int ans_L;struct Edge{int Next;int mark;Edge(int Next_ = -1,int mark_ =-1):Next(Next_),mark(mark_){}};vector<Edge> G[maxn];queue<int > q;void addEdge(int u,int v,int mark){G[u].push_back(Edge(v,mark) );}void bfs(){ int pre; int i,t,len,edge; while(!q.empty()) q.pop();     q.push(n);//     for(i=0;i<10;i++){//     printf("%d ",step[i]);// }     step[n] = 0;     while(!q.empty()){   //给每个节点记录到目标节点的距离       pre = q.front();      q.pop();     len =  G[pre].size();     //printf("len = %d ",len);     for(i=0; i<len; i++){      t = G[pre][i].Next;      //printf("%d %d\n",pre,t);      if(step[t] == -1){      step[t] = step[pre] +1;      q.push(t);  } } }}void bfs_ans(){  /*思路有问题,有可能求出的答案不是一条路径因为该方法是根据每一个数取其所有下一步节点的最小值,应该是取step值一样的所有下一步节点的最小值因为我们需要找一条路径*/ int pre; int i,t,len,edge,mini,j; while(!q.empty()) q.pop(); vis[1] = 1; q.push(1); while(!q.empty()){  //从多条最短路径中寻找字典序最小的那条     pre = q.front(); q.pop(); len = G[pre].size(); mini = 1e9+5;  //ans[step[pre]] = mini = 1e9+5;  不能这么初始化,因为有可能之前ans[step[pre]]被赋值过 for(i=0;i<len;i++){if(step[G[pre][i].Next] == step[pre] - 1){mini = min (mini,G[pre][i].mark); }}                          for(i=0;i<len;i++){                  //根据最短的那条边,我们可以把可能经过的点存入队列,注意不要重复 if(step[G[pre][i].Next] == step[pre] - 1){if(G[pre][i].mark == mini && step[G[pre][i].Next] != 0){  if(!vis[G[pre][i].Next]){   /*注释掉超时 */  vis[G[pre][i].Next] = !vis[G[pre][i].Next];   printf("%d %d\n",pre,G[pre][i].Next);   q.push(G[pre][i].Next); }}}}printf("#%d %d\n",step[pre],mini);ans[step[pre]] = min(mini,ans[step[pre]]); }}void bfs_a(){int deep = step[1];int i,d,v,ch,L,len,pre,mini,j;vector<int > v1;vector<int > v2;v1.push_back(1);for(d=deep;d>=1;d--){  //floor        len = v1.size();//        for(i=0;i<len;i++){//        printf("%d ",v1[i]);//}//puts("!");mini = INF; for(i=0;i<len;i++){  //prepre = v1[i];//printf("pre = %d\n",pre);L = G[pre].size();for(j=0;j<L;j++){ //chch = G[pre][j].Next;//printf("ch = %d\n",ch);if(step[ch] == step[pre]-1 && G[pre][j].mark < mini){    mini = G[pre][j].mark;} }}//printf("d = %d %d\n",d,mini);for(i=0;i<len;i++){pre = v1[i];L = G[pre].size();for(j=0;j<L;j++){ //chch = G[pre][j].Next;if(step[ch] == step[pre]-1 && G[pre][j].mark == mini && !vis[ch]){    //vis数组去掉还是TLE    vis[ch] = 1;      v2.push_back(ch);} }}v1 = v2;v2.clear();//printf("mini %d %d\n",d,mini);ans[d] = mini;}} void pritf(int cur){int len  = G[cur].size();for(int i=0;i<len;i++){printf("%d %d\n",cur,G[cur][i].Next);}system("pause");}int main(){int i,j,k;int u,v,mark;while(scanf("%d%d",&n,&m) == 2){for(i=0;i<maxn;i++){G[i].clear();}for(i=0;i<m;i++){scanf("%d%d%d",&u,&v,&mark);addEdge(u,v,mark);addEdge(v,u,mark);}//pritf(1);    memset(step,-1,sizeof(step));bfs();//for(int i=1;i<=n;i++){//printf("%d %d\n",i,step[i]);//}//system("pause");ans_L =  step[1];    memset(vis,0,sizeof(vis));bfs_a();printf("%d\n%d",ans_L,ans[ans_L]);for(i=ans_L-1;i>=1;i--){printf(" %d",ans[i]);}puts("");}return 0;}

!!!!!

注意点:1. 根据每个节点来扩展其所有孩子,一个queue来根据每个节点距离值来更新答案,对于每个节点,我们找到其最小的颜色值相连的孩子节点,然后把该节点放入队列,利用该颜色值更新答案。但是这样做问题在于,最终的找到的路径不是联通的,只是确保一层接着一层,以下数据为例,从1号出发,到达2,3号节点的颜色值相同,更新a【0】,然后把2,3放入队列,接着以2为起点,4,5号节点选择最小的颜色值4号节点,更新a【1】,以3起点找到经过颜色值最小边的孩子,更新a【1】,然后以4号节点为根,更新a【2】,!!!!错了,因为我们是走的3好节点,所以四号节点没有价值了。

/*
wrong:
9 9
1 2 1
1 3 1
2 4 2
2 5 3
3 6 1
6 8 5
4 7 1
7 9 2
8 9 2


*/





0 0