您的位置:首页 > 其它

LightOJ-1031-区间dp,dfs

2016-10-18 20:07 369 查看
题目大意:有n张卡片,有两个人,每次可以从左边或者右边拿走几张卡片,他们都是想自己赢,所以每次选择都是最优的,问最后差值是多少;

题目解析:对于区间[l,r],用dp[l,r]表示其区间能选择的最大值,那么假设从左边拿走了i个卡片,那么第二个人能选的最大值就是dp[l+i][r],第一个就是sum[r]-sum[l-1]-dp[l+i][r],所以dp[l][r]=max(dp[l][r],sum[r]-sum[l-1]-dp[l+i][r]),这里我们可以dfs,记忆化搜索来减少时间复杂度;

AC代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
const int inf=0x3fffffff;
bool vis[110][110];
int sum[110],dp[110][110],a[110];
int dfs(int l,int r)
{
if(l>r)	return 0;
if(vis[l][r])	return dp[l][r];
if(l==r)	return a[l];
dp[l][r]=-inf;
int	all=sum[r]-sum[l-1],i;
for(i=1;l+i<=r+1;i++)
{
dp[l][r]=max(dp[l][r],all-dfs(l+i,r));
}
for(i=1;r-i>=l-1;i++)
{
dp[l][r]=max(dp[l][r],all-dfs(l,r-i));
}
vis[l][r]=1;
return dp[l][r];
}
int main()
{
int cas,c,i,n;
scanf("%d",&cas);
for(c=1;c<=cas;c++)
{
memset(sum,0,sizeof(sum));
memset(vis,0,sizeof(vis));
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
printf("Case %d: %d\n",c,2*dfs(1,n)-sum
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: