您的位置:首页 > 移动开发

【HDU6196 2017 ACM ICPC Asia Regional Shenyang Online C】【爆搜 + 剪枝】happy happy happy 爸爸儿子轮流两头取数 爸爸想输且输少

2017-09-11 09:53 471 查看


happy happy happy

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 143    Accepted Submission(s): 22


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 (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

 

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 100, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
int a
;

int mn

, mx

;
int ST;
int LIM = 0 * CLOCKS_PER_SEC;
void init()
{
MS(mn, 63);
MS(mx, -63);
for (int i = 1; i <= n + 1; ++i)
{
mn[i][i - 1] = mx[i][i - 1] = 0;
}
for (int l = n; l >= 1; --l)
{
for (int r = l; r <= n; ++r)
{
int ll = l, rr = r;
int sub;
if (a[ll] >= a[rr])sub = a[ll++];
else sub = a[rr--];
gmax(mx[l][r], a[ll] + mx[ll + 1][rr] - sub);
gmin(mn[l][r], a[ll] + mn[ll + 1][rr] - sub);
gmax(mx[l][r], a[rr] + mx[ll][rr - 1] - sub);
gmin(mn[l][r], a[rr] + mn[ll][rr - 1] - sub);
}
}
}
int ANS;
void dfs(int l, int r, int dif)
{
if (l > r)
{
gmax(ANS, dif);
return;
}
if (dif + mn[l][r] >= 0) return;	//哪怕取一个最小值,都会赢了儿子,是个无效状态
if (dif + mx[l][r] <= ANS) return;	//哪怕取一个最大值,差值都依然太小了,最优性剪枝
if (dif + mx[l][r] < 0)				//取一个最大值,使得差值尽可能小,最优性剪枝
{
gmax(ANS, dif + mx[l][r]);
return;
}

int sub;
if (a[l] >= a[r])sub = a[l++];
else sub = a[r--];

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

//<1>取l,变成dfs(l + 1, r, dif + a[l]);
dfs(l + 1, r, dif + a[l] - sub);
//<2>取r,变成dfs(l, r - 1, dif + a[r]);
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]);
init();

ST = clock();

ANS = -inf;
dfs(1, n, 0);

if (ANS == -inf)
{
puts("The child will be unhappy...");
}
else
{
printf("%d\n", -ANS);
}
}
return 0;
}
/*
【trick&&吐槽】
我的天,这数据水爆了啊,在0ms就可以AC了啊

【题意】
从1到n共计n(90)个物品,每个物品有一个价值a[]

小孩先手。小孩爸爸轮流做游戏。
爸爸每次可以取最左边或最右边的物品。
小孩每次选价值最大的{最左边,最右边}的物品,如果价值一样大, 则选取最左边的物品。

问你,爸爸想要输(价格严格小),而且差值尽可能少的最小差值是多少。

【分析】
首先,我们DP两个东西——
1, mx[l][r]表示对于区间[l, r],儿子先手,爸爸所能拿到的最大价值差值(差值是爸爸减儿子)
2, mn[l][r]表示对于区间[l, r],儿子先手,爸爸所能拿到的最小价值差值(差值是爸爸减儿子)

那么——
我们尝试使用搜索解决这个问题

dfs(l, r, dif)表示当前还没有取的区间范围是[l, r],儿子先手,此时爸爸减儿子的差值为dif。

那么——
1,这时先考虑剪枝——

设置初始ANS = -inf;

void dfs(int l, int r, int dif)
{
if (dif + mn[l][r] >= 0) return;	//哪怕取一个最小值,都会赢了儿子,是个无效状态
if (dif + mx[l][r] <= ANS) return;	//哪怕取一个最大值,差值都依然太小了,最优性剪枝
if (dif + mx[l][r] < 0)				//取一个最大值,使得差值尽可能小,最优性剪枝
{
gmax(ANS, dif + mx[l][r]);
}
}

2,再模拟儿子的操作,获得新的(l, r, dif)

3,接着需要进一步地考虑爸爸的操作——
<1>取l,变成dfs(l + 1, r, dif + a[l]);
<2>取r,变成dfs(l, r - 1, dif + a[r]);

4,考虑如何获得DP数组mn[][]和mx[][]——

mn[i][i - 1] = mx[i][i - 1] = 0;

for(int l = n; l >= 1; --l)
{
for(int r = l; r <= n; ++r)
{
先模拟儿子的操作,获得新的(ll, rr)
然后考虑父亲的操作——
1,取ll:
gmax(mx[l][r], a[ll] + mx[ll + 1][rr]);
gmin(mn[l][r], a[ll] + mn[ll + 1][rr]);
2,取rr:
gmax(mx[l][r], a[rr] + mx[ll][rr - 1]);
gmin(mn[l][r], a[rr] + mn[ll][rr - 1]);

}
}

【时间复杂度&&优化】
O(0)

*/


最后排名还不错呀~

抱claris的大腿是开心呀!

这个1003明显有难以解决的数据,但是竟然听csy写一个极值的DP就0ms搜过去了…… 



吃惊。

感觉bitset过的人一样很吃惊2333。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: