极其简单的最短路问题【BFS】【图论】

>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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值