W3 school 菜鸟教程 我要自学网 信息学奥赛NOI 花哥的博客 不逼自己一把,怎知自己有多优秀——校长语录

一个输入引起的超时

引言

最的在做一本通网站上的题目,各种超时让人有些烦恼。今天一大早就做一本通网站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能过。取消同步无用。

posted @ 2020-02-24 12:37  耍人  阅读(318)  评论(0编辑  收藏  举报