题意:蜘蛛侠可以上下跳,问如何跳可以使得达到的最高高度尽可能小。并且最后的位置要在地面。
解题思路:首先记录跳的所有高度和sum,蜘蛛侠所能达到的最高高度肯定在1-sum之间(否则不可能做到),标准的二分模型。同时dp[i][j]表示第i次跳到高度为j是否可行。所以dp[i][j]是一个bool变量。这里的状态方程比较好处理,详见代码。求出最小的高度,剩下的就是用dfs去搜索路径,最开始以为会超时,结果1A。。爽!!
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 100;
int n,ans,height[maxn];
char path[maxn];
bool dp[maxn][1005],flag;
bool check(int len)
{
memset(dp,false,sizeof(dp));
dp[1][height[1]] = true;
for(int i = 1; i < n; i++)
for(int j = 0; j <= len; j++)
{
if(dp[i][j] == false) continue;
if(j + height[i+1] <= len)
dp[i+1][j+height[i+1]] = true;
if(j - height[i+1] >= 0)
dp[i+1][j-height[i+1]] = true;
}
return dp[n][0];
}
void dfs(int cur,int len)
{
if(flag) return;
if(cur == n)
{
if(len - height[cur] != 0) return;
for(int i = 1; i < n; i++)
printf("%c",path[i]);
printf("D\n");
flag = true;
return;
}
if(len + height[cur] <= ans)
{
path[cur] = 'U';
dfs(cur+1,len + height[cur]);
}
if(len - height[cur] >= 0)
{
path[cur] = 'D';
dfs(cur+1,len - height[cur]);
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
int sum = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d",&height[i]);
sum += height[i];
}
int l = 0, r = sum, mid;
ans = -1, flag = false;
while(l <= r)
{
mid = (l + r) >> 1;
if(check(mid))
{
ans = mid;
r = mid - 1;
}
else l = mid + 1;
}
if(ans == -1)
printf("IMPOSSIBLE\n");
else dfs(1,0);
}
return 0;
}