1. 程式人生 > >1661】Help Jimmy(記憶化搜素,dp)

1661】Help Jimmy(記憶化搜素,dp)

題幹:

解題報告:

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就可以了,這樣減少了程式碼出錯概率。

  其六,遞迴函式中的狀態轉移要想清楚,到底是由哪些狀態轉移而來,或者想,可以轉移到哪些狀態去。