【HYSBZ - 1088 】掃雷Mine (簡單dp)
阿新 • • 發佈:2018-11-22
題幹:
相信大家都玩過掃雷的遊戲。那是在一個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 ;
}