题目: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;
}