Problem
有0和1两个王国共派出N个人参加两轮预选赛,每名选手必须且只能参加一轮预选赛,最后每轮预选赛中得分前K高的晋级决赛。已知第i个人参加第一轮预赛的得分Xi、参加第二轮预赛的得分Yi和国籍Zi,求所有晋级决赛的1王国的选手最高的得分总和。
Hint
Xi 之间的值互不相同, Yi 之间的值互不相同。
对于 30%数据, N≤20;
对于 100%数据, N≤200, Xi, Yi 的总和小于 2^31。
Solution
这题乍一眼看上去很不可做,所以比赛时我只打了暴力(虽然爆0了,且原因至今未知)。
然而正解却是一个神奇的DP。
我们观察到它的N非常小,于是百思不得其解便可以为所欲为——我们可以枚举一个分界线,表示第一轮预选赛中排名第K的人。我们设他在第一轮预选赛中的得分为x。
那么我们可以发现,对于所有0国的人i,若Xi<x,则显然把他丢进第一轮里。我们把除过这些人以外的人的信息丢进一个a数组中,按照Yi从大到小排序(原因待会再告诉你)。
然后我们可以设f[i][j]表示在前i个选手中,有j个选手参加了第一轮预选赛并且晋级时1王国的选手最高的得分总和。
对于每个0国的人,若j<k,则我们可以让他参加第一轮,即得转移方程:
f[i+1][j+1]=max(f[i+1][j+1],f[i][j]);
而无论如何我们都可以让他参加第二轮,即:
f[i+1][j]=max(f[i+1][j],f[i][j])
对于每个1国的人,若Xi≥x且j<k,我们也可以让他参加第一轮,即:
f[i+1][j+1]=max(f[i+1][j+1],f[i][j]+Xi);
而若i-j<k,则说明参加第二轮且晋级(因为我们上面说了按Yi从大到小排序,所以这i-j个参加第二轮的人肯定晋级了)的人还不足k,还可以再添点,于是让这个人去参加第二轮可以晋级,即:
f[i+1][j]=max(f[i+1][j],f[i][j]+Yi);
若i-j≥k,则说明已有i-j个人去参加了第一轮。因为那参加第一轮的j个人肯定都晋级了:对于j个人中的0国人l,由于我们之前已经把Xl<x(不能晋级第一轮)的人全都筛掉了,所以剩下的0国人参加了第一轮就肯定能晋级;而对于1国人l,我们只有当他能晋级第一轮的时候才会让他去参加第一轮,否则让他去参加第二轮就会使答案有增无减。
综上,i+1这个人只能去参加第二轮,而他去参加第二轮不可以晋级,即:
f[i+1][j]=max(f[i+1][j],f[i][j])
于是我们做N轮DP即可解决问题。
时间复杂度:O(n3)O(n3)。
Code
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define N 201
#define fo(i,a,b) for(i=a;i<=b;i++)
int i,j,n,k,X[N],Y[N],Z[N],boun,x,m,f[N][N],ans;
struct comp
{
int num,x,y,z;
}a[N];
inline bool compare(comp a,comp b)
{
return a.y>b.y;
}
int main()
{
scanf("%d%d",&n,&k);
fo(i,1,n)scanf("%d%d%d",&X[i],&Y[i],&Z[i]);
fo(boun,1,n)
{
x=X[boun];
m=0;
fo(i,1,n)
if(Z[i]||X[i]>=x)
{
a[++m].num=i;
a[m].x=X[i];
a[m].y=Y[i];
a[m].z=Z[i];
}
sort(a+1,a+m+1,compare);
memset(f,254,sizeof f);
f[0][0]=0;
fo(i,0,m-1)
fo(j,0,min(i,k))
if(f[i][j]>=0)
{
if(!a[i+1].z)
{
if(j<k)f[i+1][j+1]=max(f[i+1][j+1],f[i][j]);
f[i+1][j]=max(f[i+1][j],f[i][j]);
continue;
}
if(a[i+1].x>=x&&j<k)f[i+1][j+1]=max(f[i+1][j+1],f[i][j]+a[i+1].x);
f[i+1][j]=max(f[i+1][j],f[i][j]+(i-j<k?a[i+1].y:0));
}
fo(i,0,min(m,k))ans=max(ans,f[m][i]);
}
printf("%d",ans);
}

本文介绍了一种通过动态规划解决特定竞赛晋级问题的方法。在有限的参赛者数量下,通过枚举分界线并利用DP状态转移方程,确定两轮预选赛后来自指定国家的选手最高得分总和。
1105

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



