HDU 6196 happy happy happy（卡时剪枝）

happy happy happy

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

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.

Input
There are T test cases (T≤2).
For each test case:
the first line only contains a number n (1≤n≤90&&n%2==0)
The second line contains n integers: a1,a2…an(1≤ai≤105).

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
2017 ACM/ICPC Asia Regional Shenyang Online

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

题目大意

有一个数字数字序列，父亲和孩子玩游戏，孩子先手，每个人没次只能从最左边或最右边那一个数字，拿完为止，分数高的人获胜。每次孩子那最左边和最右边中大的一个，如果两遍一样则拿左边的。父亲想输并且孩子的分数$-$自己的分数最小。问这个最小的分数。

解题思路

由于总石子数不大，可以考虑搜索。先DP预处理出每个区间分数差值的最大最小值，然后利用这个结果作为估值函数搜索。可是这样还会TLE，学习了一下大佬的写法，尝试卡一下时间就过了=_=

AC代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
#include <string>
#include <map>
#include <ctime>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long
#define fi first
#define se second
#define mem(a,b) memset((a),(b),sizeof(a))
#define sqr(x) ((x)*(x))

const int MAXN=90+3;
int N, a[MAXN];
int the_min[MAXN][MAXN], the_max[MAXN][MAXN];//区间[i, j]孩子得分减去自己得分的最小／最大值
int ans;
int ST;//计时起点
int LIM=1*CLOCKS_PER_SEC;//设定时间上限的秒数（CLOCKS_PER_SEC表示一秒钟内CPU运行的时钟周期数）

void pre_work()
{
ans=INF;
for(int i=1;i<=N+1;++i)
{
the_min[i][i-1]=the_max[i][i-1]=0;
for(int j=i;j<=N+1;++j)
{
the_min[i][j]=INF;
the_max[i][j]=-INF;
}
}
for(int l=N;l>0;--l)//预处理出任意一个区间
for(int r=l;r<=N;++r)
{
int ll=l, rr=r;
int sub=a[ll]>=a[rr]?a[ll++]:a[rr--];//孩子的操作
the_max[l][r]=max(the_max[l][r], sub-a[ll]+the_max[ll+1][rr]);
the_min[l][r]=min(the_min[l][r], sub-a[ll]+the_min[ll+1][rr]);
the_max[l][r]=max(the_max[l][r], sub-a[rr]+the_max[ll][rr-1]);
the_min[l][r]=min(the_min[l][r], sub-a[rr]+the_min[ll][rr-1]);
}
}

void dfs(int l, int r, int dif)
{
if(l>r)//搜索终点
{
ans=min(ans, dif);
return ;
}
if(dif+the_max[l][r]<=0)//无论怎么选自己都会赢
return ;
if(dif+the_min[l][r]>=ans)//没有当前答案优
return ;
if(dif+the_min[l][r]>0)//找到更优的情况
{
ans=min(ans, dif+the_max[l][r]);
return ;
}
int sub=a[l]>=a[r]?a[l++]:a[r--];//孩子的操作
if (clock() - ST > LIM)//判断是否到达时间上限
return;
dfs(l+1, r, dif-a[l]+sub);//自己选择左边的
dfs(l, r-1, dif-a[r]+sub);//自己选择右边的
}

int main()
{
while(~scanf("%d", &N))
{
for(int i=1;i<=N;++i)
scanf("%d", &a[i]);
pre_work();
ST = clock();//设定计时起点
dfs(1, N, 0);
if(ans==INF)
puts("The child will be unhappy...");
else printf("%d\n", ans);
}

return 0;
}