HDU 6386 Age of Moyu (最短路变形+堆优化)

Age of Moyu

Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 3125    Accepted Submission(s): 981


 

Problem Description

Mr.Quin love fishes so much and Mr.Quin’s city has a nautical system,consisiting of N ports and M shipping lines. The ports are numbered 1 to N. Each line is occupied by a Weitian. Each Weitian has an identification number.

The i-th (1≤iM) line connects port Ai and Bi (AiBi) bidirectionally, and occupied by Ci Weitian (At most one line between two ports).

When Mr.Quin only uses lines that are occupied by the same Weitian, the cost is 1 XiangXiangJi. Whenever Mr.Quin changes to a line that is occupied by a different Weitian from the current line, Mr.Quin is charged an additional cost of 1 XiangXiangJi. In a case where Mr.Quin changed from some Weitian A's line to another Weitian's line changes to Weitian A's line again, the additional cost is incurred again.

Mr.Quin is now at port 1 and wants to travel to port N where live many fishes. Find the minimum required XiangXiangJi (If Mr.Quin can’t travel to port N, print −1 instead)

 

 

Input

There might be multiple test cases, no more than 20. You need to read till the end of input.

For each test case,In the first line, two integers N (2≤N≤100000) and M (0≤M≤200000), representing the number of ports and shipping lines in the city.

In the following m lines, each contain three integers, the first and second representing two ends Ai and Bi of a shipping line (1≤Ai,BiN) and the third representing the identification number Ci (1≤Ci≤1000000) of Weitian who occupies this shipping line.

 

 

Output

For each test case output the minimum required cost. If Mr.Quin can’t travel to port N, output −1 instead.

 

 

Sample Input

 

3 3 1 2 1 1 3 2 2 3 1 2 0 3 2 1 2 1 2 3 2

 

 

Sample Output

 

1 -1 2

 

 

Source

2018 Multi-University Training Contest 7

 

 

Recommend

chendu   |   We have carefully selected several similar problems for you:  6408 6407 6406 6405 6404 

 

#include<bits/stdc++.h>
using namespace std;

#define debug puts("YES");
#define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++)
#define read(x,y) scanf("%d%d",&x,&y)
const int  maxn =2e5+5;
///BFS+优先队列的做法
///链式前向星
struct node{int u,nxt,w;};
node edge[maxn<<2];///链式前向星数组开两倍
int head[maxn],tot;
void init(){ memset(head,-1,sizeof(head)); tot=0; }
void add(int x,int y,int z) { edge[tot]=node{y,head[x],z} , head[x]=tot++; }
/*
题目大意:给定一个图,
边上有颜色序号区分,从不同的颜色需要经过答案权重加一,
问从1到n最小的权重是多少。

这道题的关键是如何剪枝,算法采用最短路的情况,
就是差分约束,每算出一个点就对其余相邻点做差分约束,
采用优先队列保证每次采用的都是最短距离的节点,
然后考虑会有这么个情况,
就是一个稍微长点的路径经过一个算出来的距离稍短的节点,
可能因为所经过的颜色不同而产生更优解,
所以标记一个点的代价时,不再和以前一样只是判别走没走过,
还要附带上前驱节点的集合,
如果发现更短,则清空当前节点的前驱集合,这是特别的地方。
集合用set来表示,不必含有相同的前驱节点集合


*/
int n,m,a,b,c;
///最短路结构体
struct road {
int dis,u;
int pre,fa;///记录前驱节点fa,pre记录上一次的轮胎记录
bool operator<(const road &y) const
{
    return dis>y.dis;///优先级
}
};

set<int> sta[maxn];///这回用的不是vis数组去重了,而是判断前缀。
int dis[maxn];
int bfs()
{
    for(int i=1;i<=n;i++) sta[i].clear();
    memset(dis,0xf,sizeof(dis)); dis[1]=0;
    priority_queue<road> pq;
    pq.push(road{dis[1],1,-1,-1});

    while(!pq.empty())
    {
        road tp=pq.top(); pq.pop();

        int pre=tp.pre,u=tp.u,d=tp.dis;
        if(d>dis[u]) continue;
        else if(d==dis[u])
        {
            if(sta[u].find(tp.fa)!=sta[u].end()) continue;
            sta[u].insert(tp.fa);
        }
        else
        {
            dis[u]=d;///更新距离数组
            sta[u].clear();
            sta[u].insert(tp.fa);
        }

        for(int i=head[u];~i;i=edge[i].nxt)
        {
            int v=edge[i].u,now=edge[i].w;
            if(tp.fa==v) continue;
            if(dis[v]>=dis[u]+(pre!=now))///差分约束
            {
                dis[v]=dis[u]+(pre!=now);
                pq.push(road{dis[v],v,now,u});
            }
        }
    }
    return (dis[n]>=100007)?-1:dis[n];
}

int main()
{
    while(read(n,m)!=EOF)
    {
        init();
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
        }///建图
        printf("%d\n",bfs());
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值