题目链接
http://codeforces.com/contest/388/problem/C
题目大意
给你n堆牌, 每堆牌有m张牌, 其分数为a1~am, 两个人轮流选牌,第一个人只能拿最左边的牌, 第二个人只能拿最右边的牌(可以从不同牌堆中选), 每个人都用最优选法使自己获得的值最大, 让你输出牌选完后两个人的分数
思路
这题看似是一道很难的博弈题,但是仔细思考一下就会发现, 由于他们有只能拿最左边或最右边的牌的限制,如果牌堆个数是偶数,明显就是两人平分, 如果是奇数个,那么先拿的人就可以贪心地先去拿中间牌分数比较高的牌堆,就变成很简单的博弈了
代码
#include<bits/stdc++.h>
using namespace std;
struct P
{
int a[1005];
int v, l;
bool operator < (P& x)
{
return v < x.v;
}
}cnt1[105], cnt2[105];
int main()
{
int n, ta = 0, tb = 0;
scanf("%d", &n);
for(int i=0; i<n; ++i)
{
int m;
scanf("%d", &m);
if(m&1)
{
for(int j=0; j<m; ++j)
scanf("%d", &cnt1[ta].a[j]);
cnt1[ta].v = cnt1[ta].a[m/2];
cnt1[ta].l = m;
++ta;
}
else
{
for(int j=0; j<m; ++j)
scanf("%d", &cnt2[tb].a[j]);
cnt2[tb].l = m;
++tb;
}
}
sort(cnt1, cnt1+ta);
int ans1 = 0, ans2 = 0;
for(int i=ta-1; i>=0; --i)
{
for(int j=0; j<cnt1[i].l/2; ++j)
ans1 += cnt1[i].a[j];
for(int j=cnt1[i].l/2+1; j<cnt1[i].l; ++j)
ans2 += cnt1[i].a[j];
if((ta-i)&1) ans1 += cnt1[i].v;
else ans2 += cnt1[i].v;
//cout<<ans1<<' '<<ans2<<endl;
}
for(int i=0; i<tb; ++i)
{
for(int j=0; j<cnt2[i].l; ++j)
{
if(j < cnt2[i].l/2) ans1 += cnt2[i].a[j];
else ans2 += cnt2[i].a[j];
}
//cout<<ans1<<' '<<ans2<<endl;
}
printf("%d %d\n", ans1, ans2);
return 0;
}
反思
这种题应该把自己代入题目的角色中,再去想我该怎样取才能使分数尽量高,有时候看似很难的博弈题可能只是一道贪心题