POJ 1015 Jury Compromise ---- DP

把p-d作为约束,p+d最大作为优化目标。 倒序枚举m以在空间上压缩掉n。普遍流传的解法恐怕根本就不是dp,也无法证明正确性,否则0/1背包就多了一种从未有过的解法。而且其记录路径的做法我也觉得是错的,我用的是更保守的做法,用一个三维数组,包含了n这一维的信息来记录路径

debug个了一个下午,问题基本上都出在C中多维数组的使用上。比如说你定义了dp[n][m],但你把它当dp[m][n]用,也不会有异常,因为C不检查下标越界,也不存在实际意义上的多维数组,数据存取是通过将“多维数组”的多维下标映射到一维空间上完成的。这导致即使某一维下标越界(负值都可以),只要计算得到的一维空间上的位置没超过数组存储空间的边界就可以。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 1 << 30;
int dp[21][801];
pair<int, int> id[201][21][801];
int d[201];
int p[201];
int n,m,cas = 0;

void outputID(int i, int j, int k)
{
    int res = id[i][j][k].first;
    if(j > 1)
        outputID(id[i][j][k].second, j - 1, k - (p[res] - d[res]));
    cout << " " << res;
}

int main()
{
//    freopen("1015.in","r",stdin);
    ios::sync_with_stdio(false);
    while(cin >> n >> m, n)
    {
        for(int i = 1; i <= n; ++i)
            cin >> p[i] >> d[i];
        memset(dp,-1,sizeof(dp));
        dp[0][20*m] = 0;
        for(int i = 1; i <= n; ++i
//        , cout << endl
        )
        {
            for(int j = m; j; --j
//            , cout << endl
            )
            {
                for(int k = 0; k <= 20*m*2; ++k)
                {
                    id[i][j][k] = id[i - 1][j][k];

                    int kk = k - (p[i] - d[i]);
                    if(0 <= kk && kk <= 20*m*2 && ~dp[j - 1][kk] && dp[j - 1][kk] + p[i] + d[i] > dp[j][k])
                    {
                        dp[j][k] = dp[j - 1][kk] + p[i] + d[i];
                        id[i][j][k].first = i;
                        id[i][j][k].second = i - 1;
                    }
//                    if(~dp[j][k])
//                        cout << k << ":" << dp[j][k] << ":" << id[i][j][k].second << "." << id[i][j][k].first << " ";
                }
            }
        }
        int ansk = INF, ans = -INF;
        for(int k = 20*m*2; ~k; --k)
            if(~dp[m][k] && (abs(k - 20*m) < abs(ansk - 20*m) || (abs(k - 20*m) == abs(ansk - 20*m) && ans < dp[m][k])))
                ans = dp[m][k], ansk = k;
        cout << "Jury #" << ++cas << endl;
        cout << "Best jury has value " << (ans + ansk - 20*m) / 2 << " for prosecution and value " << (ans - ansk + 20*m) / 2 << " for defence:" << endl;
        outputID(n, m, ansk);
        cout << endl << endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值