HDU 6196 happy happy happy (2017沈阳网赛 - 搜索 + dp + [黑科技。。。])

题意:

儿子和爸爸选牌, 每一次每个人只能从最左边选择或者在最右边选择, 儿子的决策是 选左边 和 右边最大的那个位置, 如果一样大, 选择左边, 爸爸的决策是为了让儿子赢, 问你 如果儿子能赢 爸爸与儿子的最小分数差是多少, 如果无论如和 爸爸都赢儿子 输出The child will be unhappy...

思路:

很乱搞的一个题目。。

我们先预处理出两个dp 来, dp1[i][j]表示 i~j 这个区间 儿子先手 爸爸拿牌的最小值,

dp2[i][j] 则表示i~j 这个区间儿子先手, 爸爸拿牌的最大值。

有了两个dp 就可以搜索了。

dfs(l,r,dif) 表示搜索l~r 这个区间, 目前爸爸减儿子的分数为dif。

然后dfs里模拟儿子和爸爸就行了, 儿子直接按照贪心来, 爸爸 的话 就都搜一遍。

dfs里得加点剪枝。

如果目前dif + dp1(最小值) >= 0 的话, 肯定是爸爸赢儿子了 return掉。

如果dif + dp2 还不如 ans(目前最优解), 也剪掉。

如果选择dp2 还小于0 就更新一下答案, 也没必要继续搜了。

当然感觉这些都没啥卵用。。

加一个小黑科技, 看到快超时时, 直接return好了。

    if (clock() - ST > LIM) {
        return;
    }



#include <cstdio>
#include <cstring>
#include <algorithm>
#include <time.h>
using namespace std;

const int maxn = 100;
const int inf = 0x3f3f3f3f;
int a[maxn];
int dp1[maxn][maxn], dp2[maxn][maxn], sum[maxn];
int ST;
int LIM = 0 * CLOCKS_PER_SEC;
int DP1(int l,int r){
    int& ans = dp1[l][r];
    if (ans != -1) return ans;

    if (l > r) {
        return ans = 0;
    }
    if (a[l] >= a[r]){
        ans = min(DP1(l + 1, r - 1) + a[r], DP1(l + 2, r) + a[l + 1]);
    }
    else {
        ans = min(DP1(l+1, r-1) + a[l], DP1(l, r-2) + a[r-1]);
    }
    return ans;
}
int DP2(int l,int r){
    int& ans = dp2[l][r];
    if (ans != -1) return ans;

    if (l > r) {
        return ans = 0;
    }
    if (a[l] >= a[r]){
        ans = max(DP2(l + 1, r - 1) + a[r], DP2(l + 2, r) + a[l + 1]);
    }
    else {
        ans = max(DP2(l+1, r-1) + a[l], DP2(l, r-2) + a[r-1]);
    }
    return ans;
}


int ans;

void dfs(int l,int r,int dif){
    if (l > r){
        ans = max(ans, dif);
        return;
    }
    if (dif + 2 * dp1[l][r] - (sum[r] - sum[l-1]) >= 0) return;
    if (dif + 2 * dp2[l][r] - (sum[r] - sum[l-1]) <= ans) return;
    if (dif + 2 * dp2[l][r] - (sum[r] - sum[l-1]) < 0){
        ans = max(ans, dif + 2 * dp2[l][r] - (sum[r] - sum[l-1]));
        return;
    }
    if (clock() - ST > LIM) { /// 醉了。。
        return;
    }
    if (a[l] >= a[r]){
        dfs(l + 1, r - 1, dif + a[r] - a[l]);
        dfs(l + 2, r, dif + a[l + 1] - a[l]);
    }
    else {
        dfs(l, r - 2, dif + a[r-1] - a[r]);
        dfs(l + 1, r - 1, dif + a[l] - a[r]);
    }
}
int main(){
    int n;
    while(~scanf("%d", &n)){
        for (int i = 1; i <= n; ++i){
            scanf("%d", a + i);
            sum[i] = sum[i-1] + a[i];
        }
        ST = clock();
        memset(dp1,-1,sizeof dp1);
        memset(dp2,-1,sizeof dp2);
        DP1(1, n); DP2(1, n);
        ans = -inf;
        dfs(1, n, 0);
        ans = -ans;
        if (ans >= inf){
            puts("The child will be unhappy...");
        }
        else {
            printf("%d\n", ans);
        }
    }


    return 0;
}

happy happy happy

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 530    Accepted Submission(s): 157


Problem Description
Today, Bob plays with a child. There is a row of  n  numbers. One can takes a number from the left side or the right side in turns and gets the grade which equals to the number. Bob knows that the child always chooses the bigger number of the left side and right side. If the number from two sides is equal, child will always choose the left one.
The child takes first and the person who gets more grade wins. The child will be happy only when he wins the game. 
Bob wants to make the child happy, please help him calculate the minimal difference of their grades when he loses the game. 
 

Input
There are T test cases ( T2 ).
For each test case: 
the first line only contains a number  n  ( 1n90&&n%2==0
The second line contains  n  integers:  a1,a2an(1ai105) .
 

Output
For each test ease, you should output the minimal difference of their grades when Bob loses the game. If Bob can't lose the game, output "The child will be unhappy...".
 

Sample Input
  
  
4 2 1 5 3 2 2 2
 

Sample Output
  
  
5 The child will be unhappy...
 

Source
 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:   6205  6204  6203  6202  6201 
 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值