题意:
给出一个序列,其中距离不超过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个时,才会有新的数字加入到状态中。
代码一:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define mem(a) memset(a,0,sizeof(a)) 5 #define mp(x,y) make_pair(x,y) 6 const int INF = 0x3f3f3f3f; 7 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; 8 inline ll read(){ 9 ll x=0,f=1;char ch=getchar(); 10 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 11 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 12 return x*f; 13 } 14 ////////////////////////////////////////////////////////////////////////// 15 const int maxn = 1e3+10; 16 17 int n; 18 ll a[maxn]; 19 int dp[maxn][1<<10],full; 20 21 int nx(int p,int st){ 22 if(n-(p+1) > 9) return (1<<9) | (st>>1); 23 else return st>>1; 24 } 25 26 int dfs(int p,int st){ 27 if(p == n) return st==0; 28 if(dp[p][st] != -1) return dp[p][st]; 29 dp[p][st] = 0; // 二维 表示在p这个位置[保证可以记忆化,不被覆盖] 从p开始的10个数字的状态为st时是否可消 30 31 if((st&1) == 0) dp[p][st] = dfs(p+1,nx(p,st)); 32 else{ 33 int cnt = 0; 34 for(int i=1; i<10; i++){ 35 if((1<<i & st) == (1<<i)){ 36 // if (1<<i&st){ 37 // cout << "aa " << i << " " << st << " " << (1<<i&st) << endl; 38 cnt++; 39 if(cnt > 5) break; 40 if(a[p] == a[p+i]){ 41 int newst = st & ~(1<<i) & ~1; 42 if(dfs(p+1,nx(p,newst))){ 43 dp[p][st] = 1; 44 break; 45 } 46 } 47 } 48 } 49 } 50 return dp[p][st]; 51 } 52 53 int main(){ 54 while(scanf("%d",&n) != EOF){ 55 memset(dp,-1,sizeof(dp)); 56 for(int i=1; i<=n; i++) 57 a[n-i] = read(); 58 full = (1<<min(n,10)) - 1; 59 60 cout << dfs(0,full) << endl; 61 } 62 63 return 0; 64 }
代码二: 直接dfs模拟
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define mem(a) memset(a,0,sizeof(a)) 5 #define mp(x,y) make_pair(x,y) 6 const int INF = 0x3f3f3f3f; 7 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; 8 inline ll read(){ 9 ll x=0,f=1;char ch=getchar(); 10 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 11 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 12 return x*f; 13 } 14 ////////////////////////////////////////////////////////////////////////// 15 const int maxn = 1e3+10; 16 map<int,int> mp; 17 map<int,int>::iterator it; 18 int a[maxn],used[maxn]; 19 20 int dfs(int n){ 21 while(n>0 && used[n]) n--; 22 if(n==0) return 1; 23 if(n==1) return 0; 24 int i = 0; 25 int j = n-1; 26 while(i<=5){ 27 if(j<=0) return 0; 28 if(used[j]) { 29 j--; 30 continue; 31 } 32 if(a[n] == a[j]){ 33 used[j] = 1; 34 if(dfs(n-1)) return 1; 35 used[j] = 0; 36 } 37 i++; 38 j--; 39 } 40 return 0; 41 } 42 43 int main(){ 44 int n; 45 while(scanf("%d",&n)!=EOF){ 46 mp.clear(); 47 mem(used); 48 for(int i=1; i<=n; i++){ 49 a[i] = read(); 50 mp[a[i]]++; 51 } 52 53 int flag = 1; 54 for(it=mp.begin(); it!=mp.end(); it++){ 55 if(it->second % 2){ 56 flag = 0; 57 break; 58 } 59 } 60 if(!flag){ 61 cout << 0 << endl; 62 continue; 63 } 64 // cout << 1 << endl; 65 cout << dfs(n) << endl; 66 } 67 68 69 return 0; 70 }