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;

}

 

 


你可能感兴趣的:(HDU)