<题目链接>
题目大意:
给定一张无向图,有n个点m条边,从一条边到另一条边,如果两边的指不同 花费就要+1,如果相同就不需要花费。 先从1走到n问最小花费是多少。(第一条边的花费都是1)
解题分析:
开始还以为类似于Dijkstra这样的贪心过程是伪的,但是本题确实是dijkstra,不过需要进行一些巧妙的变形,用一个set记录到达每个点的最优花费的所有的路径的前一条边(因为到达一个点的最优路径可能有多条),主要用于判断下一步花费是否需要+1。
//set[u]表示当前的u距离最短时,u的前一条边所有种类 #include <bits/stdc++.h> using namespace std; const int N = 1e5+5 , M = 2e5+5; const int INF = 0x3f3f3f3f; #define REP(i,s,t) for(int i=s;i<=t;i++) int n,m; int vis[N]; struct Edge{ int to,nxt,val; }e[M<<1]; int cnt,head[N]; set<int>s[N]; inline void init(){ cnt=0; for(int i=0;i<=n;i++)s[i].clear(); memset(head,-1,sizeof(head)); } inline void add(int u,int v,int w){ e[++cnt]=(Edge){ v,head[u],w };head[u]=cnt; } struct Node{ int loc,dist; bool operator < (const Node & tmp)const{ return dist>tmp.dist; } }node[N]; void Dij(){ priority_queue<Node>q; REP(i,1,n){ vis[i]=0,node[i].loc=i,node[i].dist=INF; } node[1].dist=0; q.push(node[1]); while(!q.empty()){ int u=q.top().loc;q.pop(); if(vis[u])continue; vis[u]=1; for(int i=head[u];~i;i=e[i].nxt){ int v=e[i].to; int w; if(s[u].count(e[i].val))w=node[u].dist; else w=node[u].dist+1; if(node[v].dist>w){ node[v].dist=w; s[v].clear(); //因为v点的最优花费发生更新,所以这里需要清空 s[v].insert(e[i].val); q.push(node[v]); } else if(node[v].dist==w){ s[v].insert(w); } } } } int main(){ while(~scanf("%d%d",&n,&m)){ init(); REP(i,1,m){ int u,v,w;scanf("%d%d%d",&u,&v,&w); add(u,v,w);add(v,u,w); } Dij(); if(node[n].dist==INF)puts("-1"); else printf("%d ",node[n].dist); } }