*【HDU - 4272 】LianLianKan (dfs 或 状压dp,贪心不行)
題干:
I like playing game with my friend, although sometimes looks pretty naive. Today I invent a new game called LianLianKan. The game is about playing on a number stack.?
Now we have a number stack, and we should link and pop the same element pairs from top to bottom. Each time, you can just link the top element with one same-value element. After pop them from stack, all left elements will fall down. Although the game seems to be interesting, it's really naive indeed.?
To prove I am a wisdom among my friend, I add an additional rule to the game: for each top element, it can just link with the same-value element whose distance is less than 6 with it.?
Before the game, I want to check whether I have a solution to pop all elements in the stack.?
Input
There are multiple test cases.?
The first line is an integer N indicating the number of elements in the stack initially. (1 <= N <= 1000)?
The next line contains N integer ai indicating the elements from bottom to top. (0 <= ai <= 2,000,000,000)
Output
For each test case, output “1” if I can pop all elements; otherwise output “0”.
Sample Input
2 1 1 3 1 1 1 2 1000000 1Sample Output
1 0 0題目大意:
給你有n個數的棧,連續(xù)的6個數中有兩個一樣的數可以消除,一次只能消除兩個,且最頭上那個必須被選擇(也就是每次必須從頭上開始選),問最終這個棧的數能不能被消完。
解題報告:
? ?剛開始貪心最近的,發(fā)現不行,因為可能要消遠的 ?因為可能別人需要用這個來減少距離。后來嘗試貪心最遠的,,都WA了,看來只能dfs了、、
錯誤代碼:
#include<bits/stdc++.h> #define ll long long using namespace std; ll a[1005]; int main() {int n;while(~scanf("%d",&n)) {vector<ll> vv;for(int i = 1; i<=n; i++) {scanf("%lld",&a[i]);}for(int i = n; i>=1; i--) {vv.push_back(a[i]);}if(n%2 == 1) {printf("0\n");continue;}vector<ll> :: iterator it;int flag = 0;while(1) {it = vv.begin();flag = 0;for(int i = 1; i<=5; i++) {if( ( it+i ) == vv.end()) {flag=0;break;}if(*(it+i) == (*it)) {flag=1;vv.erase(it+i);vv.erase(it);break;}}if(flag == 0) break;if(vv.size() == 0) break;}if(vv.size()) printf("0\n");else printf("1\n");}return 0 ; }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 using namespace std; const int MAX = 2e5 + 5; ll a[MAX]; bool vis[MAX]; int flag,n; void dfs(int cur) {while(cur <= n && vis[cur]) cur++;if(cur > n) {//已經說明vis[n]=1了所以不用判斷了 flag = 1;return ;}//if(cur == n) return;//因為已經判斷奇偶了,所以這一步也不需要了if(flag) return;vis[cur]=1;int cnt = 0;int j=cur+1;for(; cnt<=5;) {if(j>=n+1) return;if(vis[j]) {j++;continue;}//if(cur+i>n) return;if(a[j] == a[cur]) {vis[j]=1;dfs(cur+1);vis[j]=0;}cnt++;j++;if(flag) return;}vis[cur]=0; } map<ll,int>mp; int main() {while(~scanf("%d",&n)) {flag = 0;mp.clear();for(int i = n; i>=1; i--) {scanf("%lld",&a[i]);vis[i]=0;mp[a[i]]++;}if(n%2 == 1 ) {printf("0\n");continue;}map<ll,int>::iterator it;for(it=mp.begin(); it!=mp.end(); it++) {if((it->second)%2==1) {flag = 2;break;}}if(flag == 2) {puts("0");continue;}dfs(1);if(flag) puts("1");else puts("0");}return 0 ; }AC代碼3:(把dfs中while那一部分給改了)
#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 using namespace std; const int MAX = 2e5 + 5; ll a[MAX]; bool vis[MAX]; int flag,n; void dfs(int cur) {if(cur > n) {flag = 1;return;}if(vis[cur]) {dfs(cur+1); return;}if(flag) return;vis[cur]=1;int cnt = 0;int j=cur+1;for(; cnt<=5;) {if(j>=n+1) return;if(vis[j]) {j++;continue;}//if(cur+i>n) return;if(a[j] == a[cur]) {vis[j]=1;dfs(cur+1);vis[j]=0;}cnt++;j++;if(flag) return;}vis[cur]=0; } map<ll,int>mp; int main() {while(~scanf("%d",&n)) {flag = 0;mp.clear();for(int i = n; i>=1; i--) {scanf("%lld",&a[i]);vis[i]=0;mp[a[i]]++;}if(n%2 == 1 ) {printf("0\n");continue;}map<ll,int>::iterator it;for(it=mp.begin(); it!=mp.end(); it++) {if((it->second)%2==1) {flag = 2;break;}}if(flag == 2) {puts("0");continue;}dfs(1);if(flag) puts("1");else puts("0");}return 0 ; }去掉map:
#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 using namespace std; const int MAX = 2e5 + 5; ll a[MAX]; bool vis[MAX]; int flag,n; ll fk; void dfs(int cur) {if(cur > n) {flag = 1;return;}if(vis[cur]) {dfs(cur+1);return;}if(flag) return;vis[cur]=1;int cnt = 0;int j=cur+1;for(; cnt<=5;) {if(j>=n+1) return;if(vis[j]) {j++;continue;}//if(cur+i>n) return;if(a[j] == a[cur]) {vis[j]=1;dfs(cur+1);vis[j]=0;}cnt++;j++;if(flag) return;}vis[cur]=0; } map<ll,int>mp; int main() {while(~scanf("%d",&n)) {flag = 0;mp.clear();for(int i = n; i>=1; i--) {scanf("%lld",&a[i]);vis[i]=0;fk ^= a[i];}if(n%2 == 1 || fk != 0 ) {printf("0\n");continue;}dfs(1);if(flag) puts("1");else puts("0");}return 0 ; }比較美觀的版本:(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 using namespace std; const int MAX = 2e5 + 5; ll a[MAX]; bool vis[MAX]; int flag,n; void dfs(int cur) {if(cur > n) {flag = 1; return;}if(vis[cur]) {dfs(cur+1); return;}vis[cur]=1;int cnt = 0;int now=cur+1;for(; cnt<=5;) {if(now>n) return;if(vis[now]) {now++;continue;}if(a[now] == a[cur]) {vis[now]=1;dfs(cur+1);vis[now]=0;}cnt++; now++;if(flag) return;}vis[cur]=0; } int main() {while(~scanf("%d",&n)) {flag = 0;for(int i = n; i>=1; i--) {scanf("%lld",&a[i]);vis[i]=0;}if(n%2 == 1 ) {printf("0\n");continue;}dfs(1);if(flag) puts("1");else puts("0");}return 0 ; }總結:
? 剛開始一直dfs的是TLE或者是WA,,仔細原因就不深究了(太麻煩了),但是代碼確實有一個地方寫的有問題,首先剛開始dfs是這么實現的。。。
void dfs(int cur) {while(cur <= n && vis[cur]) cur++;if(cur > n && vis[n]) {flag = 1;return ;}if(cur > n) return;if(vis[cur]) {dfs(cur+1);return;}if(flag) return;vis[cur]=1;for(int i = 1; i<=5; i++) {if(vis[cur+i]) continue;if(a[cur+i] == a[cur]) {vis[cur+i]=1;dfs(cur+1);vis[cur+i]=0;}if(flag) return;}vis[cur]=0; }這就顯然有問題了,,(不保證是原始版本了反正我隨便挑了個WA的代碼就放上來了),主要就是在于for(int i = 1; i<=5; i++)這里就不對,,因為沒有考慮到中間有的數字可能已經被使用過了、題目中說的連續(xù)5個數字,,不是真正的物理連續(xù),而是消除之后剩下的數字的連續(xù)的五個,所以不能這么寫代碼、并且還有小錯誤不斷:經常把a[cur]寫成a[i]了。。
還有一個地方,主函數中判斷每個數出現次數是否是偶數次,經檢驗,這個剪枝就算不加,也不會TLE。。。
?
方法2:(狀壓dp)
看了別人的代碼發(fā)現還有一種神奇的狀壓dp方法。
首先討論一點最遠能消除的地方,比如點的位置是x,如若想要消除x+1位置處的值,那么至少也得在x-4處開始消除,所以x后面最多能有4個被消除,也就是最多能下落4個位置,能夠消除的最遠距離是x+9,不會超過10個狀態(tài)。
我們用dp[i][j]代表到第i個元素,且包含他和后面的十個元素狀態(tài)為j時,這個是否合法。其中狀態(tài)j:如果某一位為1,代表已經消除,某一位為0,代表沒有消除。
那個t的作用是:判斷狀態(tài)的能否達到的時候要注意判斷中間有多少個已經被消除的。
//狀壓dp #include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> using namespace std;const int MAXN = 1<<10; const int bit = 9;int data[MAXN]; bool dp[MAXN][MAXN];int main() {int i, j, k, N;while(scanf("%d", &N) != EOF){memset(data, -1, sizeof(data));memset(dp, 0, sizeof(dp));for(i=N; i>0; i--){scanf("%d", &data[i]);}dp[0][0] = true;for(i=1; i<=N; i++)for(j=0; j<MAXN; j++){if(dp[i-1][j] == true){///這種狀態(tài)存在if(j & 1){///本位已經被消除dp[i][j>>1] = true;}else{int t = 0;///紀錄已經被消除的,狀態(tài)1表示被消除,0表示沒有for(k=1; k<=bit; k++){if(!(j&(1<<k)) && k-t <=5 &&data[i] == data[i+k]){///可以消除,兩者之間的距離應該不超過6dp[i][(j>>1)|(1<<(k-1))] = true;}else if(j & (1<<k))t++;}}}}if(dp[N][0] == true)printf("1\n");elseprintf("0\n");}return 0; }再貼兩個記憶化dp的博客:鏈接? 和? 鏈接
?
總結
以上是生活随笔為你收集整理的*【HDU - 4272 】LianLianKan (dfs 或 状压dp,贪心不行)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: rasman.exe - rasman是
- 下一篇: 【CF - 699C】 Vacation