题解 UVA323 【Jury Compromise】

读完题,很容易想到这是一道背包问题 ,但就是做不来,可以看到,方案既与差值有关,又跟和有关,那么可以考虑根据差值或和来考虑状态,可以考虑\(f[i][j][k]\)表示前\(i\)个人选了\(j\)个人并且差值为\(k\)的和最大的方案

那么状态该如何转移呢?

考虑第\(i\)个人选或不选

若不选第\(i\)个人

很明显\(f[i][j][k]=f[i-1][j][k])\)

若选第\(i\)个人

\(i\)个人的差值已经定了,那么前\(i\)个人的差值就是\(k-(p[i]-d[i])\)

可以得出\(f[i][j][k]=max(f[i][j][k],f[i-1][j-1[k-(p[i]-d[i])])\)

从题目中可以看出,差值的范围\(\left [-400,400 \right]\)那么可以直接枚举所有差值转移即可

解决了第一小问,接下来就是输出方案,可以考虑把每个状态从哪一个状态转移存起来,可以通过判断\(f[i][j][k]\)\(f[i-1][j][k]\)的关系,若相等,则说明可以不选\(i\),若不等,则说明\(i\)一定被选

代码如下

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

int f[205][25][805], p[205], d[205], tot;

void output(int i,int j,int k)//输出方案
{
    int ans[25], cnt = 0, P = 0, D = 0;
    while(j)
    {   
        if(f[i][j][k] == f[i - 1][j][k])
            i--;
        else 
        {
            ans[++cnt] = i;
            k -= (p[i] - d[i]);
            P += p[i];
            D += d[i];
            j--, i--;
        }
    }
    printf("Jury #%d\n", ++tot);
    printf("Best jury has value %d for prosecution and value %d for defence:\n", P, D);
    for (int u = cnt; u >= 1;u--)
        printf(" %d", ans[u]);
    printf("\n\n");//注意要多输出一个换行
}

int main()
{
    int n, m;
    while(scanf("%d%d",&n,&m)&&(n!=0||m!=0))//读入多组数据
    {
        for (int i = 1; i <= n;i++)
            scanf("%d%d", &p[i], &d[i]);
        memset(f, -0x3f, sizeof(f));
        f[0][0][400] = 0;
        for (int i = 1; i <= n;i++)
        {
            for (int j = 0; j <= m;j++)
            {
                for (int k = 0; k <= 800; k++)
                {
                    f[i][j][k] = f[i - 1][j][k];
                    if(j < 1)//因为可以一个人都不选,所以j从0开始,所以要判断j是否等于0
                        continue;
                    int t = k - p[i] + d[i];
                    if(t < 0 || t > 800)//判断是否越界
                        continue;
                    f[i][j][k] = max(f[i - 1][j - 1][t] + p[i] + d[i], f[i][j][k]);
                }
            }
        }
        for (int i = 0; i <= 400; i++)//找出差值最小的方案
        {
            if(f[n][m][400-i] >= 0 ||f[n][m][i+400] >= 0)
            {
                if(f[n][m][400-i] > f[n][m][400+i])
                {
                    output(n, m, 400 - i);
                    break;
                }
                else
                {
                    output(n, m, 400 + i);
                    break;
                }
            }
        }
    }
    return 0;
}
posted @ 2020-12-29 11:00  DSHUAIB  阅读(72)  评论(0)    收藏  举报