题意:
给出一个序列,其中距离不超过6的两个相同的数字可以消除掉(从上往下消,输入是从底向上的),问能不能全部消除。
思路:
状压dp http://www.cnblogs.com/swm8023/archive/2012/09/10/2679455.html
因为最坏情况下,它后面的四个数字能被它前面的四个数字消掉,这样它就能和原来是它后面的第9个元素相消了,最多10个状态
状态转移:
如果st的第1说明这一位位为0,已经被消掉,d[i][st]=dp(i+1,next(st))。
如果第1为为1,向后连续找至多五个为1的位,比较是否和第一位数字相同,如果相同,就将st的这两位置为0,然后
d[i][st]=d(i+1,next(newst)),newst=st&~1&~(1<<k),其中x[k]==x[i]。
next(st)这个函数是求将st传递到下一个位置时的状态,如果(n-(p+1) > 9) st=1<<9|st>>1,否则st=st>>1,因为只有当后面数字多于10个时,才会有新的数字加入到状态中。
代码一:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mem(a) memset(a,0,sizeof(a))
#define mp(x,y) make_pair(x,y)
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
//
const int maxn = 1e3+10;
int n;
ll a[maxn];
int dp[maxn][1<<10],full;
int nx(int p,int st){
if(n-(p+1) > 9) return (1<<9) | (st>>1);
else return st>>1;
}
int dfs(int p,int st){
if(p == n) return st==0;
if(dp[p][st] != -1) return dp[p][st];
dp[p][st] = 0; // 二维 表示在p这个位置[保证可以记忆化,不被覆盖] 从p开始的10个数字的状态为st时是否可消
if((st&1) == 0) dp[p][st] = dfs(p+1,nx(p,st));
else{
int cnt = 0;
for(int i=1; i<10; i++){
if((1<<i & st) == (1<<i)){
// if (1<<i&st){
// cout << "aa " << i << " " << st << " " << (1<<i&st) << endl;
cnt++;
if(cnt > 5) break;
if(a[p] == a[p+i]){
int newst = st & ~(1<<i) & ~1;
if(dfs(p+1,nx(p,newst))){
dp[p][st] = 1;
break;
}
}
}
}
}
return dp[p][st];
}
int main(){
while(scanf("%d",&n) != EOF){
memset(dp,-1,sizeof(dp));
for(int i=1; i<=n; i++)
a[n-i] = read();
full = (1<<min(n,10)) - 1;
cout << dfs(0,full) << endl;
}
return 0;
}
代码二: 直接dfs 模拟
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mem(a) memset(a,0,sizeof(a))
#define mp(x,y) make_pair(x,y)
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
//
const int maxn = 1e3+10;
map<int,int> mp;
map<int,int>::iterator it;
int a[maxn],used[maxn];
int dfs(int n){
while(n>0 && used[n]) n--;
if(n==0) return 1;
if(n==1) return 0;
int i = 0;
int j = n-1;
while(i<=5){
if(j<=0) return 0;
if(used[j]) {
j--;
continue;
}
if(a[n] == a[j]){
used[j] = 1;
if(dfs(n-1)) return 1;
used[j] = 0;
}
i++;
j--;
}
return 0;
}
int main(){
int n;
while(scanf("%d",&n)!=EOF){
mp.clear();
mem(used);
for(int i=1; i<=n; i++){
a[i] = read();
mp[a[i]]++;
}
int flag = 1;
for(it=mp.begin(); it!=mp.end(); it++){
if(it->second % 2){
flag = 0;
break;
}
}
if(!flag){
cout << 0 << endl;
continue;
}
// cout << 1 << endl;
cout << dfs(n) << endl;
}
return 0;
}