分金子
题目描述:
A、B两伙马贼意外地在一片沙漠中发现了一处金矿,双方都想独占金矿,但各自的实力都不足以吞下对方,经过谈判后,双方同意用一个公平的方式来处理这片金矿。处理的规则如下:他们把整个金矿分成n段,由A、B开始轮流从最左端或最右端占据一段,直到分完为止。
马贼A想提前知道他们能分到多少金子,因此请你帮忙计算他们最后各自拥有多少金子?(两伙马贼均会采取对己方有利的策略)
这是2017年360春招的编程最后一题,题目很有意思,两个马贼互相博弈。
解题思路:动态规划
dp[i][j]:从第i堆到第j堆,能够拿到的最多金矿。
递推公式:dp[i][j]=sum(i->j)-min(dp[i+1][j],dp[i][j+1])
min(dp[i+1][j],dp[i][j+1]):下一个人拿的最少的金矿
初始条件:dp[i][i]=a[i] //每一堆的金矿数
为了避免递归超时,选择了递推的方式。
#include<iostream>
#include<cmath>
using namespace std;
int main(){
int t;
cin>>t;
for(int k=0;k<t;k++){
int n;
cin>>n;
int dp[n+1][n+1];
int a[n+1];
for(int i=1;i<n+1;i++)
cin>>a[i];
a[0]=0;
int sum[n+1];
sum[0]=0;
for(int i=1;i<n+1;i++)
sum[i]=sum[i-1]+a[i];
for(int i=1;i<n+1;i++)
dp[i][i]=a[i];
for(int i=1;i<n;i++)
for(int j=1;j+i<=n;j++)
dp[j][i+j]=(sum[i+j]-sum[j-1])-min(dp[j+1][i+j],dp[j][i+j-1]);
cout<<"Case #"<<k+1<<": "<<dp[1][n]<<" "<<sum[n]-dp[1][n]<<endl;
}
return 0;
}