这里讨论的是最优乘车的优化!
标答请移步至 此
--------------------------------以下是原回答--------------------------------------
-
优化在于建图方式
标答中,每一条公交线路都要建$n(n-1)/2$条边
为了提升效率,我们需要减少边数
方法
利用yxc的”虚拟源点”思想,可以给每条公交线路一个专用的虚拟源点。
把每条公交线路分成相等的2块,前一块所有点与虚拟源点连边,后一块所有点与虚拟源点连边。
利用分治思想,前后2块内部各自再创建虚拟源点。
时间复杂度 $O(mnlogn)$
代码如下:
// 感谢 @Shen666 指出的用getchar优化代码
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std ;
const int N=1010 ;
int m,n ;
int h[N],e[N*2],ne[N*2],w[N*2],idx ;
int dis[N] ;
int stop[N] ;
int add_cnt ;
void add(int a,int b,int c)
{
e[idx]=b ;
w[idx]=c ;
ne[idx]=h[a] ;
h[a]=idx++ ;
}
void Add(int stop[],int start,int end)
{
add_cnt++ ;
if(start>=end) return ;
for(int i=start;i<=(start+end>>1);i++) add(stop[i],add_cnt,0) ;
for(int i=(start+end>>1)+1;i<=end;i++) add(add_cnt,stop[i],1) ;
Add(stop,start,start+end>>1) ;
Add(stop,(start+end>>1)+1,end) ;
}
void bfs() //和SPFA一个样子
{
queue<int> q ;
q.push(1) ;
memset(dis,0x3f,sizeof dis) ;
dis[1]=0 ;
while(q.size())
{
int t=q.front() ;
q.pop() ;
for(int i=h[t];~i;i=ne[i])
{
int j=e[i] ;
if(dis[j]>dis[t]+w[i])
{
dis[j]=dis[t]+w[i] ;
q.push(j) ;
}
}
}
}
int main()
{
scanf("%d%d",&m,&n),getchar() ;
add_cnt=n ;
string str ;
memset(h,-1,sizeof h) ;
while(m--)
{
int cnt=0 ;
string str ;
getline(cin,str) ;
memset(stop,0,sizeof stop) ;
for(auto ch:str)
{
if(ch==' ') cnt++ ;
else stop[cnt]=stop[cnt]*10+ch-'0' ;
}
Add(stop,0,cnt) ;
}
bfs() ;
if(dis[n]>1e9) puts("NO") ;
else printf("%d",dis[n]-1) ;
return 0 ;
}
用getchar()把一开始的回车处理掉,就不用单独处理了。
有道理诶!
优化至11毫秒,还有更快的吗
%%%
orz
%%%%
#### 优化至13ms
#### 优化至15ms
好先进的语法!值得鼓励!
dfs版本的建图方式是有问题的
4 15
11 2
1 3 4 5 9
3 6 11
2 7 8 10 11 12 13 15
这个样例就过不去,答案是2,dfs版本跑出来的是3
似乎也是诶 遇到环就处理不了。。。
已经提交工单了,再交应该就过不去了…
确实当时我大意了 提醒一下大家只有在DAG里面才可以用dfs!碰到环就不可以dfs了!
我有一个想法单是我太菜了我不敢说出来
说出来!
那个dfs的时间复杂度应该是nlogn,优化了不少,不是传统意义上的dfs爆搜。属于两个或者多个方向同时进行。类似于分治。dfs爆搜应该是直接进行搜索,把每一条通向N的路求出来,然后取一个最小值。这个时间复杂度就高了,其实作者的第一个方法和第二个方法是一样的复杂度
好的!
感谢支持
20ms优化至18ms这信说服力不够
az
如果能解释一下各个数组的含义就更好了