HDU 6386 Age of Moyu (最短路+set)

<题目链接>

题目大意:
给定一张无向图,有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\n",node[n].dist);
    }
}

 

posted @ 2019-06-01 23:14  悠悠呦~  阅读(263)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end