【训练题】拔河比赛Ⅱ

【问题描述】

  学校决定举行一次全校性的拔河比赛,以班为单位组队。我们知道影响拔河比赛胜负的因素有:参赛队的合力量、总重量和技巧。如果每只队伍的人数都一样的话,那么低年级的班级会没有获胜的希望。因此学校考虑到比赛公平性和参与的广泛性,做出如下规定:

  ◆ 每只队伍的人数不一定相同,但队员的总重量不能超过某个规定的值。
  ◆ 每只队伍的女队员必须达到一定的人数。

  多多是高二x班的体育委员,班主任将本班组队的任务交给了他。多多深知影响比赛胜败的三个关键因素中力量和重量是前提,技巧靠后期训练。因此他必须先考虑在学校规定的前提下,选那些同学才能获得最大的合力量。

【输入格式】

  第一行3个数整数:分别表示队员总重量上限W(<=4000)、多多班上学生总人数N(<=60)、女同学人数M(<=30);
  第2行一个整数,表示参赛队中必须达到的女队员人数K(<=10);
  接下来N行每行2个整数,分别表示多多班上每个同学的重量和力量,其中第3到M+2行是所有女生的重量和力量,第M+3到N+2行表示所有男同学的重量和力量,每个整数在60至180之间。

【输出格式】

  一行一个整数,合力量的最大值。

【输入样例】

400 10 3
2
90 120
80 90
100 150
110 80
150 100
120 80
90 80
80 70
120 100
110 90

【输出样例】

460

【数据范围】

共10组测试数据:(每组测试正确得10分,共100分)
对于前3组数据有n<=20、M<=10、w<=1000;
对于前5组数据有n<=30、M<=15、w<=2000;
对于前10组数据有n<=60、M<=25、w<=4000;

【题解】
穷举 + 0/1背包类的动态规划

动态规划计算,从M个女生中选择至少K个女生,体重和不超过T的情况下所能获得的最大力量:P1
动态规划计算,从N-M个男生中选择一些,体重和不超过W-T的情况下所能获得的最大力量:P2

女 d1:设置状态函数f(m,k,w)=前m个女生,选择k个女生,在体重和不超过w的情况下,所能得到的最大力量和(可用滚动数组)
  
男 d2:设置状态函数f(n,w)=前n个男生中选择一些,在体重和不超过w的情况下,所能得到的最大力量和(可用滚动数组)

把女生和男生分开来分析:
队伍的体重和不超过W,把这个W分成两部分:女生体重和不超过T,男生体重和不超过W-T,因此可以穷举T,然后p1、p2调用生成好的d1、d2。

#include<cstdio>
#include<algorithm>
#define maxn 2000
#define oo 1000000000
using namespace std;
int w,n,m,k,x,y,ans=-oo;
int gw[maxn],gp[maxn],bw[maxn],bp[maxn];
int girl[50][50][4005]={0},boy[65][4005]={0};
void read(int &x)
{
    x=0;
    bool ok=0;
    char ch;
    ch=getchar();
    while((ch>'9'||ch<'0')&&ch!='-') ch=getchar();
    while((ch>='0'&&ch<='9')||ch=='-')
    {
        if(ch=='-') ok=1;
        else x=x*10+ch-'0';
        ch=getchar();
    }
}

void in()
{
    read(w);read(n);read(m);read(k);
    for(int i=1;i<=m;i++)
    {
        read(gw[i]);
        read(gp[i]);
    }
    for(int i=1;i<=n-m;i++)
    {
        read(bw[i]);
        read(bp[i]);
    }
}

void fuck1()
{
    for(int k=0;k<=m;k++)
    for(int i=0;i<=m;i++)
    for(int j=0;j<=w;j++) girl[k][i][j]=-oo;

    for(int k=0;k<=m;k++)
    for(int j=0;j<=w;j++) girl[k][0][j]=0;

    for(int i=0;i<=m;i++)
    for(int j=0;j<=w;j++) girl[0][i][j]=0;

    //f(i,j,v)=前i个女生,选择j个女生,在体重和不超过v的情况下,所能得到的最大力量和
    for(int i=1;i<=m;i++)
    for(int j=1;j<=i;j++)
    for(int v=w;v>=1;v--)
    {
        if(i-1>=j) girl[i][j][v]=max(girl[i][j][v],girl[i-1][j][v]);
        if(v-gw[i]>=0) girl[i][j][v]=max(girl[i-1][j-1][v-gw[i]]+gp[i],girl[i][j][v]);
    }
}

void fuck2()
{
    for(int i=1;i<=n-m;i++)
    for(int j=1;j<=w;j++) boy[i][j]=-oo;

    //f(i,v)=前i个男生中,选择几个,体重和不超过v时,所能得到的最大力量和
    for(int i=1;i<=n-m;i++)
    for(int v=w;v>=1;v--)
    {
        boy[i][v]=max(boy[i][v],boy[i-1][v]);
        if(v-bw[i]>=0) boy[i][v]=max(boy[i][v],boy[i-1][v-bw[i]]+bp[i]);
    }

}

void task()
{
    fuck1();
    fuck2();
    int ans=-oo; 
    for(int t=0;t<=w;t++)
    {
        int t1=-oo,t2=-oo;
        for(int i=k;i<=m;i++) t1=max(t1,girl[m][i][t]);
        t2=max(t2,boy[n-m][w-t]);
        if(t1+t2>ans) ans=t1+t2;
    }
    printf("%d",ans);
}


int main()
{
    in();
    task();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35546348/article/details/52137346
今日推荐