zoukankan      html  css  js  c++  java
  • 【HDNOIP】HD201404最短路径

    HD201404最短路径

    【试题描述】

    a、b、c是3个互不相等的1位正数,用它们和数字0可以填满一个n行n列的方格阵列,每格中都有4种数码中的一个。填入0的格子表示障碍物,不能属于任何路径。你是否能找出一条从1行1列出发,到达n行n列且代价最小的路径呢?注意:每一格只能走向与之相邻的上、下、左、右的非0且不出界的格子。而所谓路径代价指的是路径经过的所有格子中的数字总和。请你编程求出从1行1列的位置出发到达n行n列的最小路径代价,若无法到达就输出-1。

    【输入要求】

    第一行输入数字n。
    接下来的n行每行是一个长度为n的数字串,这n个字符串就构成了一个数字符的方阵。方阵中除了'0'外,最多还可以包含3种数字符。

    【输出要求】

    仅有最小代价或-1这一个整数。

    【输入实例】

    【输入样例1】
    4
    1231
    2003
    1002
    1113
    【输入样例2】
    4
    3150
    1153
    3311
    0530
    

    【输出实例】

    【输出样例1】
    10
    【输出样例2】
    -1
    

    【其他说明】

    60%的数据,n<10,80%的数据,n<100,100%的数据,n<1000

    【试题分析】

         第一眼:这不就是迷宫吗!?看我秒过!!

         第二眼:还不太一样,迷宫是走一步ans++,这个是要加一个变量的

         第三眼:上DFS代码吧!!

    于是就花了1小时yy了这么一个代码:

    #include<iostream>
    #include<cstring>
    using namespace std;
    char map[1001][1001],cinm[1001][1001];
    int a[1001][1001],ans=0,m,n,k[1001][1001],k1[1001][1001],mk=0;//k不变,变的只是k1.
    void res(int u,int v,int i,int j)
    {
        int t=k1[u][v];
        if(u==i&&v==j) ans=t,mk=1;
        if(v<m-1&&map[u][v+1]!='#'&&a[u][v+1]>t+k[u][v+1])
        {
            k1[u][v+1]=k[u][v+1]+t;
    		a[u][v+1]=k1[u][v+1];
            res(u,v+1,i,j);
        }
        if(u>0&&map[u-1][v]!='#'&&a[u-1][v]>t+k[u-1][v])
        {
            k1[u-1][v]=k[u-1][v]+t;
    		a[u-1][v]=k1[u-1][v];
            res(u-1,v,i,j);
        }
        if(v>0&&map[u][v-1]!='#'&&a[u][v-1]>t+k[u][v-1])
        {
            k1[u][v-1]=k[u][v-1]+t;
    		a[u][v-1]=k1[u][v-1];
            res(u,v-1,i,j);
        }
        if(u<n-1&&map[u+1][v]!='#'&&a[u+1][v]>t+k[u+1][v])
        {
            k1[u+1][v]=k[u+1][v]+t;
    		a[u+1][v]=k1[u+1][v];
            res(u+1,v,i,j);
        }
    }
    int main() 
    {
        cin>>n;
        m=n;
        for(int i=0;i<n;i++)
        {
            cin>>cinm[i];
            for(int j=0;j<n;j++)
            {
                k[i][j]=cinm[i][j]-'0';
                k1[i][j]=k[i][j];
            }
    	}
        int startx=0,starty=0,endx=n-1,endy=n-1;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
    		{
                if(i==startx&&j==starty) map[i][j]='S';
                else if(i==endx&&j==endy) map[i][j]='T';
                if(k[i][j]==0)map[i][j]='#';
                else map[i][j]='.';
            }
        memset(a,1,sizeof(a));
        a[0][0]=0;
        res(startx,starty,endx,endy);
        if(mk==1)cout<<ans<<endl;
        else cout<<-1;
    }
    

        结果没有看数据范围,1000!!?

        结果对了,但是就是时间超了。

        细细想来也没有神马办法优化,罢罢罢……


    BFS:

        好了,如果DFS时间超限,那么只能用BFS了。

        于是又yy了一个BFS的代码:

        

    #include<iostream>
    using namespace std;
    char Graph[1001][1001];
    int n,m,startx,starty;
    int Dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
    int Vis[1001][1001];
    int Dis[1001][1001];
    char cinm[1001][1001],k[1001][1001];
    int Fit(int x,int y)
    {
        return (x>=1&&x<=n&&y>=1&&y<=m);
    }
    int BFS(int x,int y)
    {
        int queue[100000];
        int i,head=0,tail=0;
        queue[tail++]=x;
        queue[tail++]=y;
        Vis[x][y]=1;
        while(head<tail)
    	{
            int nowx=queue[head++];
            int nowy=queue[head++];
            for(i=0;i<4;i++)
    		{
                int tmpx=nowx+Dir[i][0];
                int tmpy=nowy+Dir[i][1];
                if(Fit(tmpx,tmpy)&&tmpx==n&&tmpy==n&&Graph[tmpx][tmpy]=='.') return Dis[nowx][nowy]+k[tmpx][tmpy];
                if(Fit(tmpx,tmpy)&&Graph[tmpx][tmpy]=='.'&&Dis[nowx][nowy]+k[tmpx][tmpy]<Dis[tmpx][tmpy])
    			{
                    Dis[tmpx][tmpy]=Dis[nowx][nowy]+k[tmpx][tmpy];
                    queue[tail++]=tmpx;
                    queue[tail++]=tmpy;
                }
            }
        }
        return 0;
    }
    int main()
    {
        int i ,j ,startx=1,starty=1;
        scanf("%d",&n);
        m=n;
        for(int i=1;i<=n;i++)
        {
            scanf("%s",cinm[i]+1);
            for(int j=1;j<=n;j++)
                k[i][j]=cinm[i][j]-'0',Dis[i][j]=999999;
    	}
    	Dis[1][1]=k[1][1];
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
    		{
                if(k[i][j]==0)Graph[i][j]='#';
                else Graph[i][j]='.';
            }
        int ans=0;
        ans=BFS(startx,starty);
        if(ans!=0) printf("%d
    ",ans);
        else printf("-1
    ");
    }
    /*
    7
    3221000
    3110012
    3123031
    1123301
    2211123
    0012333
    3312001*/
    

      结果错误。

          有些点的确能A,但是有些点死活A不了。

          突然发现了这样一个条件:最多有三个除0之外不同的数,于是又yy了一个三个队列维护的代码:

    #include<iostream>
    #include<cstring>
    #include<queue>
    using namespace std;
    inline int read() {
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    char cinm[1001][1001];
    int n,Dis[1001][1001],Vis[1001][1001],number[1001],timek,k[1001][1001];
    struct P
    {
        int x,y;
        bool operator < (const P& ths) {return Dis[x][y]<Dis[ths.x][ths.y];}
    };
    queue<P> que[3];
    int getfront()
    {
        int c=-1;
        if(que[0].size()) c=0;
        if(que[1].size()&&(c<0||que[1].front()<que[c].front())) c=1;
        if(que[2].size()&&(c<0||que[2].front()<que[c].front())) c=2;
        return c;
    }
    int Fit(int x,int y)
    {
        return (x>=1&&x<=n&&y>=1&&y<=n);
    }
    int Dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};//方向数组
    int BFS()
    {
        if(k[1][1]==0||k[n][n]==0) return -1;
        que[number[cinm[1][1]]].push((P){1,1});
    	Dis[1][1]=k[1][1];
        while(que[0].size()+que[1].size()+que[2].size())//当三个队列的大小和非空时
    	{
            int t=getfront();
    	    int x=que[t].front().x;
    		int y=que[t].front().y;//获取坐标
    		que[t].pop();
            if(x==n&&y==n) return Dis[x][y];
            if(Vis[x][y]==1) continue;
    		Vis[x][y]=1;
            for(int i=0;i<=3;i++) 
    		{
                int nx=x+Dir[i][0];
    			int ny=y+Dir[i][1];
                if(Fit(nx,ny)&&k[nx][ny]!=0&&Dis[x][y]+k[nx][ny]<Dis[nx][ny])
    			{
                    Dis[nx][ny]=Dis[x][y]+k[nx][ny];
                    que[number[cinm[nx][ny]]].push((P){nx,ny});                               
                }          
            }                                         
        }
        return -1;
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) scanf("%s",cinm[i]+1);
        memset(number,-1,sizeof(number));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
    	    {
                if(number[cinm[i][j]]<0&&cinm[i][j]!='0') number[cinm[i][j]]=timek++;//为非0元素标号
                Dis[i][j]=99999999;
                k[i][j]=cinm[i][j]-'0';
            }
        printf("%d
    ",BFS());
    }
    

    【代码】

    #include<iostream>
    #include<cstring>
    #include<queue>
    using namespace std;
    inline int read() {
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    char cinm[1001][1001];
    int n,Dis[1001][1001],Vis[1001][1001],number[1001],timek,k[1001][1001];
    struct P
    {
        int x,y;
        bool operator < (const P& ths) {return Dis[x][y]<Dis[ths.x][ths.y];}
    };
    queue<P> que[3];
    int getfront()
    {
        int c=-1;
        if(que[0].size()) c=0;
        if(que[1].size()&&(c<0||que[1].front()<que[c].front())) c=1;
        if(que[2].size()&&(c<0||que[2].front()<que[c].front())) c=2;
        return c;
    }
    int Fit(int x,int y)
    {
        return (x>=1&&x<=n&&y>=1&&y<=n);
    }
    int Dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};//方向数组
    int BFS()
    {
        if(k[1][1]==0||k[n][n]==0) return -1;
        que[number[cinm[1][1]]].push((P){1,1});
    	Dis[1][1]=k[1][1];
        while(que[0].size()+que[1].size()+que[2].size())//当三个队列的大小和非空时
    	{
            int t=getfront();
    	    int x=que[t].front().x;
    		int y=que[t].front().y;//获取坐标
    		que[t].pop();
            if(x==n&&y==n) return Dis[x][y];
            if(Vis[x][y]==1) continue;
    		Vis[x][y]=1;
            for(int i=0;i<=3;i++) 
    		{
                int nx=x+Dir[i][0];
    			int ny=y+Dir[i][1];
                if(Fit(nx,ny)&&k[nx][ny]!=0&&Dis[x][y]+k[nx][ny]<Dis[nx][ny])
    			{
                    Dis[nx][ny]=Dis[x][y]+k[nx][ny];
                    que[number[cinm[nx][ny]]].push((P){nx,ny});                               
                }          
            }                                         
        }
        return -1;
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) scanf("%s",cinm[i]+1);
        memset(number,-1,sizeof(number));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
    	    {
                if(number[cinm[i][j]]<0&&cinm[i][j]!='0') number[cinm[i][j]]=timek++;//为非0元素标号
                Dis[i][j]=99999999;
                k[i][j]=cinm[i][j]-'0';
            }
        printf("%d
    ",BFS());
    }
    
  • 相关阅读:
    寒假作业1
    自我介绍
    我罗斯方块1
    我罗斯方块
    解题报告 数学2
    解题报告 转化模式
    解题报告 数学
    经典语录
    解题报告 Trick
    解题报告 帮忙
  • 原文地址:https://www.cnblogs.com/wxjor/p/5764197.html
Copyright © 2011-2022 走看看