>Description
现在假设每条道路需要花费小X的时间为1,由于有数以万计的好朋友沿路祝贺,导致小X在通过某些路不得不耗费1的时间来和他们聊天,尽管他希望尽早见到小C,所以他希望找到一条最快时间到达电影院的路。
一开始小X在1号点,共有N个点,M条路,电影院为T号点。
>Input
第一行2个正整数,分别为n,m,t
以下m行,每行3个数,表示连接的编号以及权值
(注意,可能会有重边)
>Output
一行一个数,表示1到t的最短路
>Sample Input
10 12 6
3 9 2
6 9 2
6 2 1
3 1 1
1 9 2
2 8 2
7 10 1
7 2 1
10 0 1
8 1 1
1 5 2
3 7 2
>Sample Output
4
30%:n<=10 m<=20
60%: n<=1000 m<=20000
100%: n<=5000000 m<=10000000
>解题思路
原本打一个裸的SPFA可以得70分。
满分算法:
用BFS。因为路径长度不是1就是2,所以我们可以把2转化为1,也就是在一条权值为2的边上在加上一个点,使x->y,变成x->z->y,权值全部为1。这样每一条边的权值就是相等的了,变为谁先到t点谁就是最优的。
还要用快读。
>代码
#include<iostream>
#include<string>
#include<cstdio>
using namespace std;
struct ooo
{
int to,next;
}a[40000005];
int n,m,t,x,y,z,tt,s,head,tail,h[10000005],st[10000005],c[10000005];
bool lhq[10000005];
char cc;
int input()
{
int l=0;
cc=getchar();
while(cc<'0'||cc>'9') cc=getchar();
while(cc>='0'&&cc<='9')
{
l=l*10+cc-'0';
cc=getchar();
}
return l;
} //快读
int main()
{
n=input(),m=input(),t=input();
s=n; //s记录新建的点
for(int i=1;i<=m;i++)
{
x=input(),y=input(),z=input();
if(z==1) //权值为1时直接连接
{
a[++tt].to=y; a[tt].next=h[x]; h[x]=tt;
a[++tt].to=x; a[tt].next=h[y]; h[y]=tt; //连接x,y
}
else //为2时创点
{
s++;
a[++tt].to=s; a[tt].next=h[x]; h[x]=tt;
a[++tt].to=x; a[tt].next=h[s]; h[s]=tt; //连接x,s
a[++tt].to=s; a[tt].next=h[y]; h[y]=tt;
a[++tt].to=y; a[tt].next=h[s]; h[s]=tt; //连接s,y
}
}
head=0; tail=1; st[1]=1; lhq[1]=1; //st为队列,lhq记录某点有没有走过
while(head<tail)
{
head++;
for(int i=h[st[head]];i;i=a[i].next)
if(!lhq[a[i].to]) //没有走过
{
st[++tail]=a[i].to; lhq[a[i].to]=1;
c[a[i].to]=c[st[head]]+1; //加入队列
if(a[i].to==t) //如果到了t,就直接输出
{
printf("%d",c[t]);
return 0;
}
}
}
return 0;
}