[USACO10JAN]轮流Taking Turns(轮流吃草)

算法:博弈问题,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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值