算法:博弈问题,DP
题面描述
两头奶牛Bessi和Dessie走过一条路吃草,共n(n<=700,000)个格子,第i个格子有重量为Wi(1 <= Wi <= 2,000,000,000)的草,两牛轮流走,一旦某头牛走过了一格,那么这格的草再也不可能被任意一头奶牛吃,每格的草只能被吃一次,所以两头牛只能往后走。Bessi先走,每头牛每次都往最终自己能吃到最多草的格子走(若有多个格子则选择第一个能吃到最多草的格子),他们都知道对方也想吃到最多的草,问最后Bessi和Dessie各吃到的草的重量。
输入
第一行一个正整数n(n<=700,000);
接下来有n行,第i+1行为Wi(1 <= Wi <= 2,000,000,000).
输出
一行两个整数,之间用空格隔开,分别表示最后Bessi和Dessie各吃到的草的重量.
样例输入
6
17
5
9
10
3
8
样例输出
27 17
解题思路
博弈类题目,考虑倒推。
先定义:
f[i]表示第i格~n格(包括第i格)第一头牛(Bessi)吃到的所有草重量的最大值。
g[i]表示第i格~n格(包括第i格)第二头牛(Dessie)吃到的所有草重量的最大值(不一定吃第i格)。
两个基于题目的推论
一、因为两头牛是轮流走的,且一旦某头牛走过了一格,这格的草再也不可能被任意一头奶牛吃,那么:
对于走到第i格时,先走到的牛可以吃到草,后走到的牛一定吃不到草(因为第i格的草要么被先走到的牛吃了,要么被先走到的牛走过了)
二、由于我们默认第一头牛先走,有选择权,所以对于走到的每一格i,由推论一重新规定f[i],g[i]:
f[i]:牛吃第i格草时,第i格~n格(包括第i格)吃到的所有草重量的最大值。
g[i]:牛不吃第i格草时,第i格~n格(包括第i格)吃到的所有草重量的最大值。
设第一头牛先走且当前它走到了第i格上。此时,它有两种选择:
A.不吃这格的草 B.吃这格的草
A.第一头牛不吃第i格的草
因为第一头牛不吃第i格的草,那么它必须选择向后走到第i格后面的格子吃草,因此第i+1格和第i格一样一定是第一头牛先走到,第二头牛后走到,可以推知:
1.第一头牛可以吃第i+1格的草
2.第二头牛一定吃不到第i+1格的草(见推论一)
因此,由1得,A情况下在第i格上第一头牛吃到草的重量的最大值为:牛吃第i+1格草时 i~n格吃到草的重量的最大值
即:f[i]=f[i+1];(见推论二)
由2得,A情况下在第i格上第二头牛吃到草的重量的最大值为:
牛不吃第i+1格草时 i~n格吃到草的重量的最大值
即: g[i]=g[i+1];(见推论二)
B.第一头牛吃第i格的草
因为第一头牛吃第i格的草,那么之后该第二头牛走,它必须选择向第i格后走到后面的格子吃草,因此第i+1格一定是第二头牛先走到,第一头牛后走到,可以推知:
1.第二头牛可以吃第i+1格的草
2.第一头牛一定吃不到第i+1格的草(见推论一)
因此,由2得,B情况下在第i格上第一头牛吃到草的重量的最大值为:
牛不吃第i+1格时 i~n格吃到草的重量的最大值+第i格的草的重量
即:f[i]=g[i+1]+w[i];(见推论二)
由1,2得,B情况下在第i格上第二头牛吃到草的重量的最大值为:牛吃第i+1格草时 i~n格吃到草的重量的最大值
即:g[i]=f[i+1];(见推论二)
最后,由于第一头牛先走,有停下的选择权,因此对于每个格子关于f[i]打擂台,看第一头牛在哪个格子停下时吃到的草最多,此格子的f[i],g[i]即为答案。
代码演示
#include<cstdio>
#define N 700005
int n,w[N];
long long f[N],g[N],mx,my,i;
int main()
{
scanf("%d",&n);
for (i=1;i<=n;i++) scanf("%d",&w[i]);
f[n]=w[n];
g[n]=0;
for (i=n-1;i>=1;i--)
{
long long x=g[i+1]+w[i];
if (x>=f[i+1]) //B情况
{
f[i]=x;
g[i]=f[i+1];
}
else //A情况
{
f[i]=f[i+1];
g[i]=g[i+1];
}
}
mx=0;
for (i=1;i<=n;i++) //按f[i]打擂台
if (f[i]>mx)
{
mx=f[i];
my=g[i];
}
printf("%lld %lld\n",mx,my);
return 0;
}
&spm=1001.2101.3001.5002&articleId=102555825&d=1&t=3&u=f91640deca844677b690110b03288aa9)
1462

被折叠的 条评论
为什么被折叠?



