HDU FatMouse and Cheese (记忆化搜索+dp思想)
2016-04-08 00:49
375 查看
思路:
1)最朴素的思想就是,枚举从(0,0)出发所有可能路径,求出每一条路径的ans,打擂台比较,最大的即为答案;
2)从(0,0)出发的子问题是从(x,y)(x>0,y>0)出发,显然,对于每一个子问题都有着确定独立的最优解;所以解决了所有子问题就解决了此题;
3)dp[x][y] 记录从(x,y)出发能吃到的奶酪,所以dp[x][y]是+=路径上所有的dp[nx][ny]的奶酪
4)问题是,对于一个100*100的图每次重复枚举所有可能是很夸张的;所以可以用到一个其实很常用的东西:记忆化搜索;
(x,y) 为当前位置,(nx,ny)是下一步,在回溯的时候,肯定又会,产生(nx,ny),这时候在dfs的一开始给他加上一个标记:如果dp[nx][ny]已经有答案了,就不必再求;
这个标记就也称之为记忆化操作,实际上造成的效果避免了重复操作,只留下必要操作,就相当于把dfs变成了普通几层循环的dp。
1)最朴素的思想就是,枚举从(0,0)出发所有可能路径,求出每一条路径的ans,打擂台比较,最大的即为答案;
2)从(0,0)出发的子问题是从(x,y)(x>0,y>0)出发,显然,对于每一个子问题都有着确定独立的最优解;所以解决了所有子问题就解决了此题;
3)dp[x][y] 记录从(x,y)出发能吃到的奶酪,所以dp[x][y]是+=路径上所有的dp[nx][ny]的奶酪
4)问题是,对于一个100*100的图每次重复枚举所有可能是很夸张的;所以可以用到一个其实很常用的东西:记忆化搜索;
(x,y) 为当前位置,(nx,ny)是下一步,在回溯的时候,肯定又会,产生(nx,ny),这时候在dfs的一开始给他加上一个标记:如果dp[nx][ny]已经有答案了,就不必再求;
if(dp[x][y]) return dp[x][y];否则,比如求dp[0][0]的时候,必然要将其路径上的值再算一遍,重复计算的次数达到可怕的地步;
这个标记就也称之为记忆化操作,实际上造成的效果避免了重复操作,只留下必要操作,就相当于把dfs变成了普通几层循环的dp。
/* *********************************************** Author :angon ************************************************ */ #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <stack> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <math.h> #include <stdlib.h> #include <time.h> using namespace std; #define REP(i,k,n) for(int i=k;i<n;i++) #define REPP(i,k,n) for(int i=k;i<=n;i++) #define scan(d) scanf("%d",&d) #define scann(n,m) scanf("%d%d",&n,&m) #define LL long long #define maxn 105 #define mod 100000007 /* inline int read() { int s=0; char ch=getchar(); for(; ch<'0'||ch>'9'; ch=getchar()); for(; ch>='0'&&ch<='9'; ch=getchar())s=s*10+ch-'0'; return s; } inline void print(int x) { if(!x)return; print(x/10); putchar(x%10+'0'); } */ int n,k,dp[maxn][maxn],mp[maxn][maxn],vis[maxn][maxn]; int dir[][2]={0,1,0,-1,1,0,-1,0}; int dfs(int x,int y) { if(dp[x][y]) return dp[x][y]; int temp=0,ans=0; for(int i=1;i<=k;i++) { for(int j=0;j<4;j++) { int nx=x+dir[j][0]*i; int ny=y+dir[j][1]*i; if(nx>=0 && nx<n && ny>=0 && ny<n && vis[nx][ny]==0 && mp[nx][ny]>mp[x][y]) { vis[nx][ny]=1; //加这一句能稍快一点,不加亦可 temp = dfs(nx,ny); vis[nx][ny]=0; ans = max(ans,temp); } } } dp[x][y] = ans + mp[x][y]; //回溯的时候计算dp[x][y],自底向上,自终点向起点 return dp[x][y]; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); while(scanf("%d%d",&n,&k)) { if(n==k && n==-1) break; memset(dp,0,sizeof(dp)); memset(mp,0,sizeof(mp)); memset(vis,0,sizeof(vis)); for(int i=0;i<n;i++) for(int j=0;j<n;j++) scanf("%d",&mp[i][j]); printf("%d\n",dfs(0,0)); } return 0; }
相关文章推荐
- Hadoop学习三:hadoop的一些基本配置以及相关概念
- 多模块的覆盖率统计
- leetcode 022 Generate Parentheses
- php实习的tips(结束符的问题)
- 价值观
- javascript
- 海思lowlevel_init.S简单分析
- Android中使用RadioButton实现QQ底部图片切换
- UIViewController中addChildViewController的作用
- 技术学习
- 快速排序
- eclipse 使用gradle构建系统时候报错
- TortoiseSVN中分支和合并实践【转】
- php的tips(接口结束符问题)
- Java 日历的制作 心得 写给自己
- java基础-----2016.4.8
- 求str最长回文子序列是求这个原字符串和它反转字符串的最长公共子序列。
- MySql主从数据库和读写分离简单剖析
- 注册cell可重用单元格注意事项
- Microsoft Build 2016 有关微软公有云Azure