hdu 4272 LianLianKan (贪心可水过,不过正解是状态压缩)

http://acm.hdu.edu.cn/showproblem.php?pid=4272

 

题意:

给你一个数字栈,每次必须从栈顶开始往下找距离<=5的范围内,如果存在与栈顶相同的数字,则两个数字同时出栈,其余数字还在栈中保持相对位置不变。

思路:

比赛时,这道题目相当坑爹,才开始写的是<5 VON想到贪心模拟,可是我出了两组数据一组数据按最近贪不对,另一组按最远贪也不对。于是我们纠结啊。。。。后来知道题目出错,是<=5于是贪心水过。后来才发现贪心是不对的

这组数据:

12

1 2 2 1 3 1 1 1 1 1 1 3

应该输出0可是输出1也对。。我对这题无语了。。。我处理成<=7也对。

状态压缩,看的别人的解题报告。我想我现在的水平还没有到达这个高度,真心不好想。。。。继续加油。。

我们将设每次都是在<=5的范围内取最远的与之相同(两数出栈),则5个连续的出栈之后会形成0101010101也就是说我们只要维护一个长度为10的序列即可,只要后面存在与之相同的肯定在这10个序列里面。状态转移方程不好说,代码中讲解:

View Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll long long
#define inf 0x7f7f7f7f
#define MOD 100000007
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 100007
#define N 1007
using namespace std;
//freopen("din.txt","r",stdin);

int a[N],dp[N][1<<11];

int dfs(int dep,int msk){
    if (dep < 0){
        if (msk == 0) return 1;
        else return 0;
    }
    if (dp[dep][msk] != -1) return dp[dep][msk];
    int &res = dp[dep][msk];
    res = 0;
    //栈顶元素已经出栈
    if (!(msk&(1<<9))){
        int nsk = msk<<1;
        if (dep - 10 >= 0) nsk |= 1;//十个之后还有就不上来
        res = dfs(dep -  1,nsk);
    }
    //栈顶元素未出栈
    else{
        int ct = 0;
        int use = 0;
        int nsk = msk^(1<<9);//首先删除栈顶元素
        for (int i = 8; i >= 0; --i){
            ct++;
            if (nsk&(1<<i)){//往后查找与之相同的元素
                if (a[dep - ct] == a[dep]){
                    int tmp = nsk^(1<<i);
                    tmp <<= 1;
                    if (dep - 10 >= 0) tmp |= 1;
                    res = dfs(dep - 1,tmp);
                }
                if (res == 1) break;//找到就跳出
                use++;
                if (use >= 5) break;//保持距离<=5
            }
        }
    }
    return res;
}
int main(){
    //freopen("din.txt","r",stdin);
    int i,j;
    int n;
    while (~scanf("%d",&n)){
        for (i = 0; i < n; ++i) scanf("%d",&a[i]);
        int state = 0;
        //去前十个的状态1表示未出栈0表示出栈
        for (i = n - 1,j = 0; i >= 0 && j <= 9; --i, ++j) state = (state<<1) + 1;
        //不足十个补0
        while (j <= 9){
            state <<= 1;
            ++j;
        }
        CL(dp,-1);
        int mk = dfs(n - 1,state);
        printf("%d\n",mk);
    }
    return 0;
}

 

 


posted @ 2012-09-14 17:09  E_star  阅读(366)  评论(0编辑  收藏  举报