NOIP2017 棋盘
题目传送门(洛咕)
题目描述
有一个m×m的棋盘,棋盘上每一个格子可能是红色、黄色或没有任何颜色的。你现在要从棋盘的最左上角走到棋盘的最右下角。
任何一个时刻,你所站在的位置必须是有颜色的(不能是无色的), 你只能向上、 下、左、 右四个方向前进。当你从一个格子走向另一个格子时,如果两个格子的颜色相同,那你不需要花费金币;如果不同,则你需要花费1个金币。
另外, 你可以花费2个金币施展魔法让下一个无色格子暂时变为你指定的颜色。但这个魔法不能连续使用, 而且这个魔法的持续时间很短,也就是说,如果你使用了这个魔法,走到了这个暂时有颜色的格子上,你就不能继续使用魔法; 只有当你离开这个位置,走到一个本来就有颜色的格子上的时候,你才能继续使用这个魔法,而当你离开了这个位置(施展魔法使得变为有颜色的格子)时,这个格子恢复为无色。
现在你要从棋盘的最左上角,走到棋盘的最右下角,求花费的最少金币是多少?
输入格式
第一行包含两个正整数m, n以一个空格分开,分别代表棋盘的大小,棋盘上有颜色的格子的数量。
接下来的nn行,每行三个正整数x, y, c,分别表示坐标为(x,y)的格子有颜色c。
其中c=1代表黄色,c=0代表红色。 相邻两个数之间用一个空格隔开。 棋盘左上角的坐标为(1,1),右下角的坐标为(m,m)。
棋盘上其余的格子都是无色。保证棋盘的左上角,也就是(1,1) 一定是有颜色的。
输出格式
一个整数,表示花费的金币的最小值,如果无法到达,输出-1。
输入输出样例
输入 #1
5 7 1 1 0 1 2 0 2 2 1 3 3 1 3 4 0 4 4 1 5 5 0
输出 #1
8
输入 #2
5 5 1 1 0 1 2 0 2 2 1 3 3 1 5 5 0
输出 #2
-1
这道题算是进年来PJT3较为简单的一道,但也有很多需要注意的地方:
1.魔法只会用在空地上(显然用不着改变非同色地形)
2.用book记录会T
3.并不是只可以向右下走
这道题一上来我选的深搜(不知道为什么。。。)
这道题一上来我选的深搜(不知道为什么。。。)
没有记忆,用了book,爆T55分
#include<bits/stdc++.h> typedef long long ll; using namespace std; int a[105][105]; int ans=999999999; int n,m; int xb=0; int book[105][105]; inline int read() { int x=0,f=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=0; c=getchar();} while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();} return f?x:-x; } void dfs(int x,int y,int flag,int cnt,int col) { if(x==n&&y==n) { xb=1; ans=min(ans,cnt); return; } if(book[x][y+1]==0) { book[x][y+1]=1; if(col==a[x][y+1]) dfs(x,y+1,0,cnt,a[x][y+1]); else if(col!=a[x][y+1]&&a[x][y+1]!=0) dfs(x,y+1,0,cnt+1,a[x][y+1]); else if(a[x][y+1]==0&&flag==0) dfs(x,y+1,1,cnt+2,a[x][y]); book[x][y+1]=0; } if(book[x+1][y]==0) { book[x+1][y]=1; if(col==a[x+1][y]) dfs(x+1,y,0,cnt,a[x+1][y]); else if(col!=a[x+1][y]&&a[x+1][y]!=0) dfs(x+1,y,0,cnt+1,a[x+1][y]); else if(a[x+1][y]==0&&flag==0) dfs(x+1,y,1,cnt+2,a[x][y]); book[x+1][y]=0; } if(book[x][y-1]==0) { book[x][y-1]=1; if(col==a[x][y-1]) dfs(x,y-1,0,cnt,a[x][y-1]); else if(col!=a[x][y-1]&&a[x][y-1]!=0) dfs(x,y-1,0,cnt+1,a[x][y-1]); else if(a[x][y-1]==0&&flag==0) dfs(x,y-1,1,cnt+2,a[x][y]); book[x][y-1]=0; } if(book[x-1][y]==0) { book[x-1][y]=1; if(col==a[x-1][y]) dfs(x-1,y,0,cnt,a[x-1][y]); else if(col!=a[x-1][y]&&a[x-1][y]!=0) dfs(x-1,y,0,cnt+1,a[x-1][y]); else if(a[x-1][y]==0&&flag==0) dfs(x-1,y,1,cnt+2,a[x][y]); book[x-1][y]=0; } } int main() { memset(book,-1,sizeof(book)); int x,y,z; cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) book[i][j]=0; for(int i=1;i<=m;i++) { x=read(); y=read(); z=read(); a[x][y]=z+1; } dfs(1,1,0,0,a[1][1]); if(xb==1) cout<<ans; else cout<<-1; return 0; }
后来加了记录最优情况的剪枝,A了
#include<bits/stdc++.h> typedef long long ll; using namespace std; int a[105][105]; int ans=999999999; int n,m; int xb=0; int js[105][105]; int book[105][105]; inline int read() { int x=0,f=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=0; c=getchar();} while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();} return f?x:-x; } void dfs(int x,int y,int flag,int cnt,int col) { if(js[x][y]<=cnt) return; js[x][y]=min(js[x][y],cnt); if(x==n&&y==n) { xb=1; ans=min(ans,cnt); return; } if(book[x][y+1]==0) { if(col==a[x][y+1]) dfs(x,y+1,0,cnt,a[x][y+1]); else if(col!=a[x][y+1]&&a[x][y+1]!=0) dfs(x,y+1,0,cnt+1,a[x][y+1]); else if(a[x][y+1]==0&&flag==0) dfs(x,y+1,1,cnt+2,a[x][y]); } if(book[x+1][y]==0) { if(col==a[x+1][y]) dfs(x+1,y,0,cnt,a[x+1][y]); else if(col!=a[x+1][y]&&a[x+1][y]!=0) dfs(x+1,y,0,cnt+1,a[x+1][y]); else if(a[x+1][y]==0&&flag==0) dfs(x+1,y,1,cnt+2,a[x][y]); } if(book[x][y-1]==0) { if(col==a[x][y-1]) dfs(x,y-1,0,cnt,a[x][y-1]); else if(col!=a[x][y-1]&&a[x][y-1]!=0) dfs(x,y-1,0,cnt+1,a[x][y-1]); else if(a[x][y-1]==0&&flag==0) dfs(x,y-1,1,cnt+2,a[x][y]); } if(book[x-1][y]==0) { if(col==a[x-1][y]) dfs(x-1,y,0,cnt,a[x-1][y]); else if(col!=a[x-1][y]&&a[x-1][y]!=0) dfs(x-1,y,0,cnt+1,a[x-1][y]); else if(a[x-1][y]==0&&flag==0) dfs(x-1,y,1,cnt+2,a[x][y]); } } int main() { memset(book,-1,sizeof(book)); memset(js,127,sizeof(js)); int x,y,z; cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) book[i][j]=0; for(int i=1;i<=m;i++) { x=read(); y=read(); z=read(); a[x][y]=z+1; } dfs(1,1,0,0,a[1][1]); if(xb==1) cout<<ans; else cout<<-1; return 0; }