1. 程式人生 > >【HYSBZ - 1088 】掃雷Mine (簡單dp)

【HYSBZ - 1088 】掃雷Mine (簡單dp)

題幹:

相信大家都玩過掃雷的遊戲。那是在一個n*m的矩陣裡面有一些雷,要你根據一些資訊找出雷來。萬聖節到了
,“餘”人國流行起了一種簡單的掃雷遊戲,這個遊戲規則和掃雷一樣,如果某個格子沒有雷,那麼它裡面的數字
表示和它8連通的格子裡面雷的數目。現在棋盤是n×2的,第一列裡面某些格子是雷,而第二列沒有雷,如下圖: 
由於第一列的雷可能有多種方案滿足第二列的數的限制,你的任務即根據第二列的資訊確定第一列雷有多少種擺放
方案。

Input

  第一行為N,第二行有N個數,依次為第二列的格子中的數。(1<= N <= 10000)

Output

  一個數,即第一列中雷的擺放方案數。

Sample Input

2 1 1

Sample Output

2

Hint

解題報告:

    簡單但是十分不錯的dp題。

AC程式碼:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 10000 + 5;
ll dp[MAX][2][2];//dp[i][j][k]截止第i行,這一行為j,上一行為k。 
int a[MAX]; 
int main()
{
	int n;
	cin>>n;
	for(int i = 1; i<=n; i++) scanf("%d",a+i);
//	if(a[1] != 0) {
		dp[1][1][0]=dp[1][1][1]=dp[1][0][0]=dp[1][0][1]=1;
//	}
//	dp[1][0][0] = dp[1][1][0]=1;
	//dp[][這行][上行]   dp[i行][i行][i-1行]
	for(int i = 2; i<=n+1; i++) {
		if(a[i-1] == 1) {
			dp[i][1][0] += dp[i-1][0][0];
			dp[i][0][0] += dp[i-1][0][1];
			dp[i][0][1] += dp[i-1][1][0];
			//預設其餘的為0.。 
		}
		if(a[i-1] == 0) {
			dp[i][0][0] += dp[i-1][0][0];
		}
		if(a[i-1] == 2) {
			dp[i][1][0] += dp[i-1][0][1];
			dp[i][1][1] += dp[i-1][1][0];
			dp[i][0][1] += dp[i-1][1][1];
		}
		if(a[i-1] == 3) {
			dp[i][1][1] += dp[i-1][1][1];
		}
	}
	ll ans = 0;
	ans = /*dp[n+1][1][0] + dp[n+1][1][1] +*/ dp[n+1][0][0] + dp[n+1][0][1];
	printf("%lld\n",ans);
	return 0 ;
 }

總結:

注意合法狀態和不更新狀態的區別!!!有的是非法狀態(此題中就要是0而不是INF,因為表示的是方法數),有的是不更新狀態(此題中也是0,但是是無法到達狀態,而不是非法狀態),也就是,都是0但是含義不同!!

之所以更新成1,也是因為方法數是1。(只選這一種方法,所以方法數是1啊)

其實這個程式碼是不對的(雖然也AC了),初始化狀態的時候應該用下面那個註釋掉的,因為不然的話輸入1 1就會錯。,。。

注意不能輸出dp[n][][]的四個狀態的和!!!因為那樣就不一定滿足第n行的性質了!!!所以一定要讓狀態轉移結束以後再找結果!!不能直接輸出第n行的四個狀態的和。

附一種解法:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
ll n,x,y,c;
const int MAX = 10000 + 5;
ll dp[MAX][2][2];//dp[i][j][k]截止第i行,這一行為j,上一行為k。
int a[MAX];
int main() {
	int n;
	cin>>n;
	for(int i = 1; i<=n; i++) scanf("%d",a+i);
	dp[1][0][0] = dp[1][1][0]=1;
	//dp[][這行][上行]   dp[i行][i行][i-1行]
	for(int i = 2; i<=n+1; i++)
		for(int las = 0 ; las <= 1 ; las++)
			for(int llas = 0; llas<=1; llas++)
				for(int now = 0; now<=1; now++)
					if(las+llas+now == a[i-1])
						dp[i][now][las] += dp[i-1][las][llas] ;
	ll ans = dp[n+1][0][0] + dp[n+1][0][1];
	printf("%lld\n",ans);
	return 0 ;
}

或者:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
ll n,x,y,c;
const int MAX = 10000 + 5;
ll dp[MAX][2][2];//dp[i][j][k]截止第i行,這一行為j,上一行為k。
int a[MAX];
int main() {
	int n;
	cin>>n;
	for(int i = 1; i<=n; i++) scanf("%d",a+i);
	dp[0][0][0] = dp[0][1][0]=1;
	//dp[][下一行][這一行行]   dp[i行][i+1行][i行]
	for(int i = 1; i<=n; i++)
		for(int las = 0 ; las <= 1 ; las++)
			for(int llas = 0; llas<=1; llas++)
				for(int now = 0; now<=1; now++)
					if(las+llas+now == a[i])
						dp[i][now][las] += dp[i-1][las][llas] ;
	ll ans = dp[n][0][0] + dp[n][0][1];
	printf("%lld\n",ans);
	return 0 ;
}