一个输入引起的超时
引言
最的在做一本通网站上的题目,各种超时让人有些烦恼。今天一大早就做一本通网站1378题(http://ybt.ssoier.cn:8088/problem_show.php?pid=1378),一看数据规模不大(n=80),便随手写起来。先来一个SPFA吧,这几天觉得这算法还不错,代码也很快出来了。
//1378:最短路径(shopth) #include<iostream> #include<cstdio> using namespace std; const int N=81; const int inf=1e9; int link[N][N],msg[N][N],dis[N],p[N],n,s; int que[N*2],h=0,t=1,cx,tx; int read() { int x=0,f=1,cnt=0; char ch='\0'; while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); do { if(ch=='-')f=-1; else cnt++,x=x*10+ch-'0'; ch=getchar(); }while(ch>='0'&&ch<='9'); if(x==0&&cnt==0)x=inf; else x*=f; return x; } int main() { ios::sync_with_stdio(0); cin>>n>>s; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { cx=read(); link[i][j]=cx; if(cx<inf&&i!=j)msg[i][++msg[i][0]]=j; } //因为有负权边,不可用dijkstra,故采用SPFA for(int j=1;j<=n;j++)dis[j]=inf,p[j]=0; dis[s]=0,h=0,t=1,que[1]=s; while(h!=t) { h=h%161+1;//用循环队列 cx=que[h],p[cx]=0; for(int j=1;j<=msg[cx][0];j++) { tx=msg[cx][j]; if(dis[tx]>dis[cx]+link[cx][tx]) { dis[tx]=dis[cx]+link[cx][tx]; if(p[tx]==0) t=t%161+1,que[t]=tx,p[tx]=1; } } cout<<'('<<s<<"->"<<i<<")="<<dis[i]<<endl; } return 0; }
可提交后让我大跌眼镜,10个点超时。回头再看,感觉没问题啊,read()读入函数几乎是网传的快读程序了,应该没啥问题啊,难道SPFA出错了?虽然自我感觉没啥错,但既然报错还是改改吧,我看了下数据规模不大,干脆来个弗洛伊德得了,这个简单不易错的。可结局依然是10点超时。难道是输入错了?好吧,换一个。
//1378:最短路径(shopth) #include<iostream> #include<cstdio> using namespace std; const int N=81; const int inf=1e9; int link[N][N],msg[N][N],dis[N],p[N],n,s; //msg[x][y]存储以x为起点的边信息,msg[x][0]存储边的条数,其后依次存储各边终点 int que[N*2+3],h=0,t=1,cx,tx; //int read() //{ // int x=0,f=1,cnt=0; // //cnt记录输入的数字个数,若为0则说明只输入了一个-(无边) // char ch='\0'; // while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); // do // { // if(ch=='-')f=-1; // else cnt++,x=x*10+ch-'0'; // ch=getchar(); // }while(ch>='0'&&ch<='9'); // if(cnt==0)x=inf; // else x*=f; // return x; //} int get(string s0) { if(s0=="-")return inf; int f=1,x=0; for(int i=0;i<s0.length() ;i++) { if(s0[i]=='-')f=-1; else x=x*10+s0[i]-'0'; } return x*f; } int main() { ios::sync_with_stdio(0); cin>>n>>s; string ss; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { //cx=read(); cin>>ss; link[i][j]=get(ss); if(i!=j&&cx<inf)msg[i][++msg[i][0]]=j; } //因为有负权边,不可用dijkstra,故采用SPFA for(int j=1;j<=n;j++)dis[j]=inf,p[j]=0; dis[s]=0,h=0,t=1,que[1]=s; while(h!=t)//队列中最多n个元素,不可能队满,h=t则说明队空 { h=h%(N*2)+1;//用循环队列 cx=que[h],p[cx]=0; for(int j=1;j<=msg[cx][0];j++) { tx=msg[cx][j]; if(dis[tx]>dis[cx]+link[cx][tx])//tx的值因cx而更新 { dis[tx]=dis[cx]+link[cx][tx];//更新tx的值 if(p[tx]==0)//如果tx没在队列中则让tx入队 t=t%(N*2)+1,que[t]=tx,p[tx]=1; } } } // for(int k=1;k<=n;k++) // for(int i=1;i<=n;i++) // for(int j=1;j<=n;j++) // if(link[i][j]>link[i][k]+link[k][j]) // link[i][j]=link[i][k]+link[k][j]; for(int i=1;i<=n;i++) if(i!=s)cout<<'('<<s<<" -> "<<i<<") = "<<dis[i]<<endl; return 0; }
提交,没问题。看来真是输入出了问题。终于在之江学院石老师的指点下明白了问题所在。
前几天做1346最后一个点超时,几经周折发现取消同步后的cin能过,所以在喜欢上了取消同步的cin输入,但这一次就出在这里,取消同步后cin和getchar()就不能混用了,当然解决方案很简单,要么去掉“取消同步”,要么改掉cin,用scanf代替,问题解决。
目前个人感觉在输入方面取消同步后的cin比scanf效率高,不取消同步的cin比scanf效率低,但取消同步似乎对输出无效。典型例子就是1205汉诺塔,用cout超时,用printf能过。取消同步无用。