【POJ - 1661】Help Jimmy(记忆化搜素,dp)

版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/82809950

题干:

解题报告:

AC代码1:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
int n,x,y,maxx;
int dp[1005][2];//fg=0代表左边,fg=1代表右边 
struct Node {
	int l,r,h;
} node[1005];
bool cmp(const Node & a,const Node & b) {
	return a.h < b.h;
}
int dfs(int cur,int fg) {
	if(cur == 1) return 0;
	if(dp[cur][fg] != -1) return dp[cur][fg];
	if(cur == 1) {
		return 0;
	}
	int ans = INF;
	if(dp[cur][fg] != -1) {
		return dp[cur][fg];
	}
	int temp = cur;	
	for(int i = cur-1; i>=1; i--) {
		temp=i;
		if(node[cur].h - node[i].h > maxx) break;
		if(fg==0) {
			if(node[i].l <= node[cur].l && node[i].r >= node[cur].l) {
				ans = min(dfs(i,0)+node[cur].l-node[i].l,dfs(i,1) +node[i].r-node[cur].l );
				break;
			}
		} 
		else {
			if(node[i].r >= node[cur].r && node[i].l <= node[cur].r) {
				ans = min(dfs(i,0)+node[cur].r-node[i].l,dfs(i,1)+node[i].r-node[cur].r);
				break;
			}
		}
	}
	if(ans == INF) {
		if(node[cur].h <= maxx) return dp[cur][fg] = 0;
		else return dp[cur][fg] = ans;
	}
	else return dp[cur][fg] = ans;
}
int main()
{
	int t;
	cin>>t;
	while(t--) {
		scanf("%d%d%d%d",&n,&x,&y,&maxx);
		memset(dp,-1,sizeof (dp));
		for(int i = 1; i<=n; i++) {
			scanf("%d%d%d",&node[i].l,&node[i].r,&node[i].h);
		}
		sort(node+1,node+n+1,cmp);
		int ok=n+1;
//		node[ok].h = y;node[ok].l=node[ok].r=x;
		for(int i = n; i>=1; i--) {
			if(node[i].r >= x && node[i].l <= x) {
				ok=i;break;
			}
		}
		if(ok == n+1) {
			printf("%d\n",y);
		}
		else {
			int ans = min(dfs(ok,1) + node[ok].r-x,dfs(ok,0) + x-node[ok].l) + y;
//			int ans = min(dfs(ok,1),dfs(ok,0)) + y;
			printf("%d\n",ans);
		}

	}	
	
	return 0 ;
 } 
//1
//1
//2 3
//100
//5 6 1

AC代码2:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
int n,x,y,maxx;
int dp[1005][2];//fg=0代表左边,fg=1代表右边 
struct Node {
	int l,r,h;
} node[1005];
bool cmp(const Node & a,const Node & b) {
	return a.h < b.h;
}
int dfs(int cur,int fg) {
	if(cur == 1) return 0;
	if(dp[cur][fg] != -1) return dp[cur][fg];
//	int minn = 0x3f3f3f3f,flag=0;//0左  1右 
//	int temp=cur;
	int ans = INF;
	int temp = cur;	
	for(int i = cur-1; i>=1; i--) {
		temp=i;
		if(node[cur].h - node[i].h > maxx) break;
		if(fg==0) {
			if(node[i].l <= node[cur].l && node[i].r >= node[cur].l) {
				ans = min(dfs(i,0)+node[cur].l-node[i].l,dfs(i,1) +node[i].r-node[cur].l );
				break;
			}
		} 
		else {
			if(node[i].r >= node[cur].r && node[i].l <= node[cur].r) {
				ans = min(dfs(i,0)+node[cur].r-node[i].l,dfs(i,1)+node[i].r-node[cur].r);
				break;
			}
		}
	}
	if(ans == INF) {
		if(node[cur].h <= maxx) return dp[cur][fg] = 0;
		else return dp[cur][fg] = ans;
	}
	else return dp[cur][fg] = ans;
//	if(ans == INF) {
//		if(temp == 1) {
//			if(node[cur].h > maxx) return dp[cur][fg] = ans; 
//			else return dp[cur][fg] = 0;
//		}
//		return dp[cur][fg] = ans;
//	} 
//	else return dp[cur][fg] = ans;
}
int main()
{
	int t;
	cin>>t;
	while(t--) {
		scanf("%d%d%d%d",&n,&x,&y,&maxx);
		memset(dp,-1,sizeof (dp));
		for(int i = 1; i<=n; i++) {
			scanf("%d%d%d",&node[i].l,&node[i].r,&node[i].h);
		}
		sort(node+1,node+n+1,cmp);
		int ok=n+1;
		node[ok].h = y;node[ok].l=node[ok].r=x;
//		for(int i = n; i>=1; i--) {
//			if(node[i].r >= x && node[i].l <= x) {
//				ok=i;break;
//			}
//		}
//		int ans = min(dfs(ok,1) + node[ok].r-x,dfs(ok,0) + x-node[ok].l) + y;
		int ans = min(dfs(ok,1),dfs(ok,0)) + y;
		printf("%d\n",ans);
	}	
	
	return 0 ;
 } 

错误代码:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
int n,x,y,maxx;
int dp[1005];
struct Node {
	int l,r,h;
} node[1005];
bool cmp(const Node & a,const Node & b) {
	return a.h < b.h;
}
int dfs(int cur,int curx,int curh) {
	if(curh == 0) return 0;
	if(cur < 0) return 0;
	if(dp[cur] != -1) return dp[cur];
	int minn = 0x3f3f3f3f;
	for(int i = cur-1; i>=1; i--) {
		if(curh - node[i].h > maxx) break;
		if(node[i].l <= node[cur].l) minn = min(minn,dfs(i,node[cur].l,node[i].h)+node[cur].l-curx);
		if(node[i].r >= node[cur].r) minn = min(minn,dfs(i,node[cur].r,node[i].h)+node[cur].r-curx);
	}
	return dp[cur] = minn;
}
int main()
{
	int t;
	cin>>t;
	while(t--) {
		scanf("%d%d%d%d",&n,&x,&y,&maxx);
		memset(dp,-1,sizeof (dp));
		for(int i = 1; i<=n; i++) {
			scanf("%d%d%d",&node[i].l,&node[i].r,&node[i].h);
		}
		sort(node+1,node+n+1,cmp);
		printf("%d\n",dfs(n,x,node[n].h));
		
	}	
//	18653293769
	
	return 0 ;
 } 

总结:

   几个地方是真的坑,首先这个错误代码,记忆化搜素的设计状态我就没搞明白(因为后来我通过观察发现一维dp表示不了所有状态),于是dfs中乱设了一堆参数,结果显然都没用。

   其二,函数内部,显然要break,不能不加break,因为有上一个台子挡住了,后面即使有符合的,也不能跳上去了,所以要break。

   其三,要处理好到地面的那一步,一定是直接跳过去的(也就是 一定ans==INF),所以return的时候不能直接retrun dp[cur][fg] = ans;而应该判断是否ans==INF 如果等于的话,也就说明是到地面了,要dp[cur][fg] = 0;才可以。

   其四,有个处理技巧,让出发点当成一个新的平台,这样直接统一形式就可以了。不然的话,就跟AC代码1一样,先判断是否从出发点可以直接落到地面上,特判一下这个条件才可以。

  其五,有个技巧,就是高度都最后统一算,直接+y就可以了,这样减少了代码出错概率。

  其六,递归函数中的状态转移要想清楚,到底是由哪些状态转移而来,或者想,可以转移到哪些状态去。

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/82809950