LianLianKan HDU - 4272 状压dp
题意:长度为n(n<=1000)的栈,栈顶元素可以与下面1~5个数中相同的元素消去,问最后能都完全消去。
题解:
比如这个序列
1
2
3
4
5
6
7
8
9
10
11
2这个位置的最远可匹配位置能到11
为什么呢?
因为1这个位置可以匹配到6,那也就是说3、4、5、6这几个位置都可能被上面的匹配过(我写的序列肯定不够,将就一下)
那么剩下的序列就变成了
2
7
8
9
10
11
这样的话2的最远匹配距离就是11了
1
2
3
4
5
6
7
8
9
10
11
2这个位置的最远可匹配位置能到11
为什么呢?
因为1这个位置可以匹配到6,那也就是说3、4、5、6这几个位置都可能被上面的匹配过(我写的序列肯定不够,将就一下)
那么剩下的序列就变成了
2
7
8
9
10
11
这样的话2的最远匹配距离就是11了
所以我们要保存至少9个位置的状态,因为我们只需要确保这个位置的数是否呗抵消过
所以我们可以用1代表这个位置的数已经被抵消了,0代表没有被抵消
然后把这九个状态当作二进制形式,然后就被压缩成了一个int大小数字
所以我们可以用1代表这个位置的数已经被抵消了,0代表没有被抵消
然后把这九个状态当作二进制形式,然后就被压缩成了一个int大小数字
所以最开始状态就是dp[0][0]=1
dp[i][j]的值代表距离栈顶i-1的那个位置的数是否被抵消,是1代表被抵消了,是0代表没有抵消
dp[0][0]的设定只是为了下面程序的运行
dp[i][j]的值代表距离栈顶i-1的那个位置的数是否被抵消,是1代表被抵消了,是0代表没有抵消
dp[0][0]的设定只是为了下面程序的运行
因为题目保证首先要抵消栈顶的元素,所以我们每给dp[i][]赋值的时候必须要确保,dp[i-1][]某个位置的值是1
具体看代码
具体看代码
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 typedef long long ll; 6 using namespace std; 7 const int maxn=1005; 8 const int M=1<<9; 9 int v[maxn],dp[maxn][1<<9]; 10 int main() 11 { 12 int n; 13 while(~scanf("%d",&n)) 14 { 15 memset(dp,0,sizeof(dp)); 16 for(int i=n;i>0;--i) 17 scanf("%d",&v[i]); 18 dp[0][0]=1; 19 for(int i=1;i<=n;++i) 20 { 21 for(int j=0;j<M;++j) 22 { 23 if(dp[i-1][j]) //因为题目说明要先抵消栈顶的元素,所以每一次寻找都要找到上一个元素被抵消的位置 24 { 25 if(j&1) //这个判断是用来判断这个位置的数字是不是被它上一个位置消掉了 26 { 27 dp[i][j>>1]=1; //因为j这个状态压缩的是它下面10个位置的状态,所以j>>1就完了 28 } 29 else 30 { 31 int t=0; //记录这个位置实际上下沉了几个位置 32 for(int k=1;k<=8;++k) 33 { 34 if(!(j&(1<<k)) && k-t<=5 && v[i]==v[i+k]) 35 { 36 dp[i][(j>>1)|(1<<(k-1))]=1; 37 } 38 else if(j&(1<<k)) 39 t++; 40 } 41 } 42 } 43 } 44 } 45 if(dp[n][0]==1) 46 printf("1\n"); 47 else printf("0\n"); 48 } 49 return 0; 50 }