• NOIP2017PJ T3 棋盘


    题目链接

    题意:

    在$m*m$的方阵上,格子内有红、黄、无色三种颜色,由左上角走到右下角。移动时,只能走在有颜色的格子上,且跨越不同颜色的格子时花费$1$金币。可以花费$2$金币释放魔法,冷却一步,使得下一步内某无色格获得一种颜色。求走出棋盘耗费的最小金币。

     

    程序一(15Pt):

    习惯问题,我用的$n$和$m$意思和题面含义相反。

    对于每个有颜色的点,讨论曼哈顿距离不超过$2$的其他有颜色的点,构建有向图(实际上每个点对会被连两次,形成了无向图),跑最短路。

    然而①没有考虑终点没有颜色的情况②最短路写错了③数组开小了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int inf=1<<30;
    const int N=20;////////////////////////////////////////开小了
    const int M=1000;                                //rev to statement
    
    struct Edge{
        int to,nxt,capa;
        
    }e[N*N*8*2+3];
    
        int n,m,c[N+3][N+3],x[M+3],y[M+3];
        int pnt[N+3][N+3],h[N*N+3],top;
        int dx1[7]={0,-1,0,0,1};
        int dy1[7]={0,0,-1,1,0};
        int dx2[7]={0,-2,0,0,2};
        int dy2[7]={0,0,-2,2,0};
        int dx3[7]={0,-1,-1,1,1};
        int dy3[7]={0,-1,1,-1,1};
        
    void add(int u,int v,int c){
        top++;
        e[top].to=v;
        e[top].nxt=h[u];
        e[top].capa=c;
        h[u]=top;
        
    }
    
        int dis[N*N+3];
        int que[N*N*4+3],hd,tl;
        bool vis[N*N+3];
    
    int main(){
        scanf("%d%d",&n,&m);
        memset(c,-1,sizeof c);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&x[i],&y[i]);
            scanf("%d",&c[x[i]][y[i]]);
            
        }
        
        int cnt=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                pnt[i][j]=++cnt;
        
        top=-1;
        memset(h,-1,sizeof h);
        for(int p=1;p<=m;p++){
            int i=x[p],j=y[p];
            if(i==n&&j==n)
                continue;
            
            for(int k=1;k<=4;k++)
            if(~c[i+dx1[k]][j+dy1[k]])
                add(pnt[i][j]
                   ,pnt[i+dx1[k]][j+dy1[k]]
                   ,c[i][j]!=c[i+dx1[k]][j+dy1[k]]);
            for(int k=1;k<=4;k++)
            if(i+dx2[k]>=0&&j+dy2[k]>=0)
            if(~c[i+dx2[k]][j+dy2[k]])
            if(c[i+dx1[k]][j+dy1[k]]==-1)
                add(pnt[i][j]
                   ,pnt[i+dx2[k]][j+dy2[k]]
                   ,(c[i][j]!=c[i+dx2[k]][j+dy2[k]])+2);
            for(int k=1;k<=4;k++)
            if(~c[i+dx3[k]][j+dy3[k]])
            if(c[i][j+dy3[k]]==-1
             &&c[i+dx3[k]][j]==-1)
                add(pnt[i][j]
                   ,pnt[i+dx3[k]][j+dy3[k]]
                   ,(c[i][j]!=c[i+dx3[k]][j+dy3[k]])+2);
            
        }
        
        memset(vis,0,sizeof vis);
        for(int i=1;i<=cnt;i++)
            dis[i]=inf;
        dis[1]=0;    hd=tl=1;    que[1]=1;////////////////////起点的vis没改动
        int u,v;
        while(hd<=tl){
            u=que[hd++];////////////////////////////////////vis[u]没有改动导致错误
            for(int i=h[u];~i;i=e[i].nxt){
                v=e[i].to;
                if(dis[u]+e[i].capa<dis[v]){
                    dis[v]=dis[u]+e[i].capa;
                    if(!vis[v]){
                        vis[v]=1;
                        que[++tl]=v;
                        
                    }
                    
                }
                
            }
            
        }
        
        if(dis[pnt[n][n]]==inf)
            printf("-1");
        else 
            printf("%d",dis[pnt[n][n]]);
        
        return 0;
        
    }

    程序2(65pt):

    改用DFS,①没有发现终点无色的问题②数组开小了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int inf=1<<30;
    const int N=20;/////////////////////////////开小了
    const int M=2000;
    
        int n,m,c[N+3][N+3];                //no color:-1
        int ans[N+3][N+3];
        int dx[7]={0,-1,0,0,1};
        int dy[7]={0,0,-1,1,0};
        
    bool lim(int x,int y){
        return 1<=x&&x<=n
             &&1<=y&&y<=n;
        
    }
        
    void dfs(int x,int y,int sum,int mag){
        if(x<1||x>n||y<1||y>n)
            return ;
        if(c[x][y]==-1)
            return ;
        if(sum>=ans[x][y])
            return ;
            
        ans[x][y]=sum;
        if(x==n&&y==n)
            return ;
        
        int tx,ty;
        for(int i=1;i<=4;i++){
            tx=x+dx[i];    ty=y+dy[i];
            if(c[tx][ty]!=-1)
                dfs(tx,ty,sum+(c[x][y]!=c[tx][ty]),1);
            else 
            if(mag){
                c[tx][ty]=c[x][y];
                dfs(tx,ty,sum+2,0);
                c[tx][ty]=-1;
                
            }
                    
        }
        
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        memset(c,-1,sizeof c);
        int x,y,z;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&x,&y,&z);
            c[x][y]=z;
            
        }
        
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                ans[i][j]=inf;
        dfs(1,1,0,1);
        
        if(ans[n][n]==inf)
            printf("-1");
        else 
            printf("%d",ans[n][n]);
        
        return 0;
        
    }

    程序3(95pt):

    处理终点无色问题和输出答案冲突了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int inf=1<<30;
    const int N=100;
    const int M=2000;
    
        int n,m,c[N+3][N+3];                //no color:-1
        int ans[N+3][N+3];
        int dx[7]={0,-1,0,0,1};
        int dy[7]={0,0,-1,1,0};
        
    bool lim(int x,int y){
        return 1<=x&&x<=n
             &&1<=y&&y<=n;
        
    }
        
    void dfs(int x,int y,int sum,int mag){
        if(x<1||x>n||y<1||y>n)
            return ;
        if(c[x][y]==-1)
            return ;
        if(sum>=ans[x][y])
            return ;
            
        ans[x][y]=sum;
        if(x==n&&y==n)
            return ;
        
        int tx,ty;
        for(int i=1;i<=4;i++){
            tx=x+dx[i];    ty=y+dy[i];
            if(c[tx][ty]!=-1)
                dfs(tx,ty,sum+(c[x][y]!=c[tx][ty]),1);
            else 
            if(mag){
                c[tx][ty]=c[x][y];
                dfs(tx,ty,sum+2,0);
                c[tx][ty]=-1;
                
            }
                    
        }
        
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        memset(c,-1,sizeof c);
        int x,y,z;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&x,&y,&z);
            c[x][y]=z;
            
        }
        
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                ans[i][j]=inf;
        dfs(1,1,0,1);
        
        if(c[n][n]==-1)
            ans[n][n]=min(ans[n][n-1],ans[n-1][n])+2;////////////终点到达不了时,会出现两边都是inf,再+2
        
        if(ans[n][n]==inf)//////////////////////////////////////inf+2代表到达不了
            printf("-1");
        else 
            printf("%d",ans[n][n]);
        
        return 0;
        
    }

    程序4(100pt):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int inf=1<<30;
    const int N=100;
    const int M=2000;
    
        int n,m,c[N+3][N+3];                //no color:-1
        int ans[N+3][N+3];
        int dx[7]={0,-1,0,0,1};
        int dy[7]={0,0,-1,1,0};
        
    bool lim(int x,int y){
        return 1<=x&&x<=n
             &&1<=y&&y<=n;
        
    }
        
    void dfs(int x,int y,int sum,int mag){
        if(x<1||x>n||y<1||y>n)
            return ;
        if(c[x][y]==-1)
            return ;
        if(sum>=ans[x][y])
            return ;
            
        ans[x][y]=sum;
        if(x==n&&y==n)
            return ;
        
        int tx,ty;
        for(int i=1;i<=4;i++){
            tx=x+dx[i];    ty=y+dy[i];
            if(c[tx][ty]!=-1)
                dfs(tx,ty,sum+(c[x][y]!=c[tx][ty]),1);
            else 
            if(mag){
                c[tx][ty]=c[x][y];
                dfs(tx,ty,sum+2,0);
                c[tx][ty]=-1;
                
            }
                    
        }
        
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        memset(c,-1,sizeof c);
        int x,y,z;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&x,&y,&z);
            c[x][y]=z;
            
        }
        
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                ans[i][j]=inf;
        dfs(1,1,0,1);
        
        if(c[n][n]==-1)
            ans[n][n]=min(ans[n][n-1],ans[n-1][n])+2;
        
        if(ans[n][n]==inf+2)
            printf("-1");
        else 
            printf("%d",ans[n][n]);
        
        return 0;
        
    }

    小结:

    久违的限时训练让我手忙脚乱。记得对拍!

  • 相关阅读:
    Spring事务的传播行为、隔离级别、回滚、只读和过期
    Spring 使用XML文件的方式配置事务
    SpringJDBCTemplate
    Spring事物管理
    【运维技术】Zookeeper单机以及集群搭建教程
    【运维技术】kafka三实例集群环境搭建及测试使用
    【运维技术】redis(一主两从三哨兵模式搭建)记录
    【运维技术】shell脚本实现线程挂掉,自动重启功能
    【运维技术】slc pm 启动不了,异常排除问题记录
    【知识总结】Java类初始化顺序说明
  • 原文地址:https://www.cnblogs.com/Hansue/p/10930452.html
Copyright © 2020-2023  润新知