HDU6386 Age of Moyu (2018多校第七场1001) (建虚点+堆优化dijkstra)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=6386

题意:
n个点m条边,每个边上有一个编号;
从一个编号走到另一个编号,需要代价1;
求1到n的最小代价;

分析:
首先dfs:
对于连通的同一编号的边所连接的点,建立一条边权为1的指向一个虚点的边,同时建立边权为0的由此虚点指向这些点的边;
然后dijk;

复杂度O(m) (雾
(玄学)可能卡常,注意改掉vector,并把函数inline;

代码:

#include <bits/stdc++.h>
#define Pii pair<int,int>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const int maxm=2e5+5;
const int maxnn=1e6+5;
const int inf=2147483647;
vector<int> GG[maxn];
int from[maxm],to[maxm],c[maxm];
int n,cnt,nowc,dis[maxnn];             //cnt:n+虚点数
bool v[maxm],vis[maxnn];
struct node{
    int d,x;
    bool operator < (const node& b) const
    {return d>b.d;}
};
priority_queue<node> Q;
int _first[maxnn],_tip[maxnn],_w[maxnn],_next[maxnn],edge;
inline void dijk()
{
    int i,u,vv,len,num;
    node tmp;
    for(i=1;i<=cnt;i++) dis[i]=inf;
    dis[1]=0;
    Q.push((node){0,1});
    while(!Q.empty())
    {
        tmp=Q.top();
        Q.pop();
        u=tmp.x;
        if(vis[u]==true) continue;
        vis[u]=true;
        num=_first[u];
        while(num!=-1)
        {
            vv=_tip[num];
            if(dis[u]!=inf&&dis[vv]>dis[u]+_w[num])
            {
                dis[vv]=dis[u]+_w[num];
                Q.push((node){dis[vv],vv});
            }
            num=_next[num];
        }
    }
    return;
}
inline void dfs(int x)
{
    //add(x,cnt,1);
    _tip[++edge]=cnt;
    _w[edge]=1;
    _next[edge]=_first[x];
    _first[x]=edge;

    //add(cnt,x,0);
    _tip[++edge]=x;
    _w[edge]=0;
    _next[edge]=_first[cnt];
    _first[cnt]=edge;

    int i,len=GG[x].size(),num;
    for(i=0;i<len;i++)
    {
        num=GG[x][i];
        if(c[num]==nowc&&!v[num])
        {
            v[num]=true;
            if(from[num]==x) dfs(to[num]);
            else dfs(from[num]);
        }
    }
    return;
}
int main()
{
    int i,m;
    while(scanf("%d%d",&n,&m)==2)
    {
        edge=0;
        cnt=n;
        memset(v,0,sizeof(v));
        memset(vis,0,sizeof(vis));
        memset(_first,-1,sizeof(_first));
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&from[i],&to[i],&c[i]);
            GG[from[i]].push_back(i);
            GG[to[i]].push_back(i);
        }
        for(i=1;i<=m;i++)
            if(!v[i])
            {
                cnt++;
                nowc=c[i];
                dfs(from[i]);
            }
        dijk();
        if(dis[n]==inf) printf("-1\n");
        else printf("%d\n",dis[n]);
        //test();
        for(i=1;i<=n;i++) GG[i].clear();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值