博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【记忆化搜索】[NOIP-2017--普及组] -- 棋盘
阅读量:4539 次
发布时间:2019-06-08

本文共 2751 字,大约阅读时间需要 9 分钟。

【题目描述】 原题目
  有一个m × m的棋盘,棋盘上每一个格子可能是红色、黄色或没有任何颜色的。你现在要从棋盘的最左上角走到棋盘的最右下角。
任何一个时刻,你所站在的位置必须是有颜色的(不能是无色的),你只能向上、下、左、右四个方向前进。当你从一个格子走向另一个格子时,如果两个格子的颜色相同,那你不需要花费金币;如果不同,则你需要花费 1 个金币。
  另外,你可以花费 2 个金币施展魔法让下一个无色格子暂时变为你指定的颜色。但这个魔法不能连续使用,而且这个魔法的持续时间很短,也就是说,如果你使用了这个魔法,走到了这个暂时有颜色的格子上,你就不能继续使用魔法;只有当你离开这个位置,走到一个本来就有颜色的格子上的时候,你才能继续使用这个魔法,而当你离开了这个位置(施展魔法使得变为有颜色的格子)时,这个格子恢复为无色。
  现在你要从棋盘的最左上角,走到棋盘的最右下角,求花费的最少金币是多少?
【输入格式】
  数据的第一行包含两个正整数 m,n,以一个空格分开,分别代表棋盘的大小,棋盘上 有颜色的格子的数量。
  接下来的 n 行,每行三个正整数 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
 
图片省略~~
-------------------------------------------------------------------------------

分析:记忆化搜索, 用DP[i][j]表示走到(i,j)时的最小代价,如果当前深搜到的代价sum>=dp[i][j],直接return ; 否则更新dp[i][j]——表示这是一个更优的解,然后继续递归!与sum的判断,每一个if条件都不能省!

/*  同种颜色可以直接跳上去;/0红色,1黄色,-1空格
    跳到不同颜色花费1金币;
   op=1, 或者跳到空格-1上,开销为2,然后 再跳到有色的地方--开销1或者0;*/
-----------------------------------------------------------------------------------
 

AC题解:

  
int m,n;   //和题意描述的相反,m表示有颜色的点数,n表示正方形的边长int G[N][N];//存贮每个格点的颜色情况!int ans;int dir[4][2]={ {-1,0},{
1,0},{
0,-1},{
0,1} };int dp[N][N];//用DP[i][j]表示走到(i,j)时的最小代价void dfs(int x,int y,int sum,int op,int col){ // printf("**(%d,%d) sum=%d op=%d col=%d\n",x,y,sum,op,col); if(x==n&&y==n){ ans=min(ans,sum); // printf("________sum=%d\n",sum); return ; } for(int i=0;i<4;i++){ int dx=x+dir[i][0]; int dy=y+dir[i][1]; if(dx<1||dy<1||dx>n||dy>n) continue; if(sum>=dp[dx][dy])//进行优化,dp[][]记忆之前达到该点的最小花费! continue ; if(G[dx][dy]>=0){ if(col==G[dx][dy]){
//代价为零,同种颜色! dp[dx][dy]=sum; dfs(dx,dy,sum,0,col); } else{ //代价为1,异种颜色,可以非一次! dp[dx][dy]=sum+1; dfs(dx,dy,sum+1,0,!col); } } else{ if(op==0&&dp[dx][dy]>sum+2 ){ //上面有条件:dp[dx][dy]>sum dp[dx][dy]=sum+2; dfs(dx,dy,sum+2,1,col);//op改为1表示跳到空格上了,下一步要小心! } } }}int main(){ // freopen("checkerboard.in","r",stdin); // freopen("checkerboard.out","w",stdout); int x,y,z; scanf("%d%d",&n,&m); memset(G,-1,sizeof(G)); for(int i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&z); G[x][y]=z;//0红色,1黄色 } memset(vis,0,sizeof(vis)); ans=inf; memset(dp,inf,sizeof(dp)); dp[0][0]=0; dfs(1,1,0,0,G[1][1]);//省时需要记忆化搜索!! if(ans==inf){ printf("-1\n"); } else{ printf("%d\n",ans); } return 0;}
View Code(点开有注释呦~~)

 

转载于:https://www.cnblogs.com/zhazhaacmer/p/8796487.html

你可能感兴趣的文章
题目1014:排名
查看>>
Windows服务安装
查看>>
人工智能 1. 语音合成,语音识别,相似度,图灵机器人,智能对话
查看>>
46_并发编程-进程与线程之间的对比
查看>>
毕业设计第一周每天工作
查看>>
在VS2008中编译和使用OpenSSL
查看>>
临时邮箱
查看>>
jQuery框架分析第一章: 第一个匿名函数
查看>>
如何查看、修改Linux的系统时间
查看>>
hdu 2602 Bone Collector 01背包
查看>>
'fc' 不是内部或外部命令,也不是可运行的程序
查看>>
HTTPS工作原理-默写
查看>>
怎样从GitHub项目中,下载单个文件夹或文件
查看>>
redis安装问题
查看>>
2019 Web开发学习路线图
查看>>
鼠标点击特效
查看>>
2016年网站运维总结【转载】
查看>>
单例模式--singleton
查看>>
php课程笔记4
查看>>
比特币转账流程
查看>>