EOJ:Pro-Test Voting

——PROBLEM:某人竞选,须在各个社区争取选票,投入一定资金能够提高支持率,问如何分配资金能够使支持的人最多,并输出方案(同等条件下使第一个社区的投入最多,如果相同则第二个社区最多,依次类推)

——背包问题,麻烦在于输出方案

——url:http://202.120.106.94/onlinejudge/problemshow.php?pro_id=542

————————————————————————————————————————————————————————————

别被公式吓到,其实是个很简单的背包问题

方程:dp[i][j]=max(dp[i-1][k]+tmp)  tmp为投入J-K这么多钱给第I个社区所能得到的支持人数。

赛时一直没有AC,问题出在输出方案

原先的想法是:

dp[i][j]=max(dp[i-1][k]+tmp)  J=0->M  K=J->0

即同等条件下取前面用的钱多的方案。

但是这是有问题的

例如:

假设有三个社区,有两种方案,分别是每个社区投入23 45 20和21 50 17

在转移的时候,dp[3][88]会从dp[2][21+50]转过来而不是dp[2][23+45],而这显然不符合题目的要求。

正确的解法:

将所有的小区倒过来,即原来最后一个小区变成现在第一个小区,原来第一个小区变成现在最后一个小区。(以下均是以此为基础)

dp[i][j]=max(dp[i-1][k]+tmp)  

同等条件下取J-K最大的,即当前这个小区投入资金最多的。

如此一来,当前面的小区(即原来后面的小区)的状态一定时,当前这个小区用的钱是最多的,依次类推,即最后一个小区(原来第一个小区)用的钱是最多的。

#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
#define maxm 105
int dp[maxm][maxm],f[maxm][maxm],ans[maxm];
int i,j,k,tmp,m,n,loc,cas;
double delta[maxm],Ip[maxm],N[maxm];
int min(int a,int b)
{
    return a<b?a:b;
}
int solve(int a,double b)
{
    double tmp;
    int t;
    tmp=(b/(b+10.1)*delta[a]+Ip[a])/100*N[a];
    t= (int)(tmp+0.5);
    return min(t,N[a]);
}
int main()
{
    cas=0;
    while (1)
    {
        cas++;
        scanf("%d%d",&m,&n);
        if (m==0&&n==0)
            break;
        memset(dp,0,sizeof(dp));
        memset(ans,0,sizeof(ans));
        dp[n+1][0]=0;
        for (i=1;i<=n;i++)
            scanf("%lf%lf%lf",&N[i],&Ip[i],&delta[i]);
        for (i=n;i>=1;i--)
            for (j=m;j>=0;j--)
                for (k=0;k<=j;k++)
                {
                    tmp=solve(i,j-k);
                    if (dp[i+1][k]+tmp>dp[i][j])
                    {
                        dp[i][j]=dp[i+1][k]+tmp;
                        f[i][j]=k;
                    }
                }

        tmp=m;
        loc=1;
        while (loc!=n+1)
        {
            ans[loc]=tmp-f[loc][tmp];
            tmp=f[loc][tmp];
            loc++;
        }
        printf("Case %d: %d\n",cas,dp[1][m]);
        for (i=0;i<n-1;i++)
            printf("%d:%d ",i,ans[i+1]);
        if (n>0)
            printf("%d:%d\n",n-1,ans[n]);
    }
    return 0;
}

  

posted on 2011-08-06 22:12  风也轻云也淡  阅读(194)  评论(0编辑  收藏  举报