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;
    
}

小结:

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

猜你喜欢

转载自www.cnblogs.com/Hansue/p/10930452.html