待解决POJ 1015 Jury Compromise

一直WA 应该是有特判没有想到 待解决

这个题的收获:
1 除了dp数组外还可以额外开数组做记录的作用
2 应用了和之前Balance题里一样的思想,平移区间(最开始做的时候直接对cha[i]求了绝对值,其实是错的,动手算一下就会发现先绝对值再加和与先加和再绝对值的结果是不一样的)
3 最后打印结果的时候,要找到差最小的dp数组,注意可能出现距离400距离相等的两种情况,这时候要判断哪边和大。
4 找差最小的dp的时候,注意这个两边找的小技巧,会更快。并且注意i是从0开始取,如果从1开始取,那一些特殊情况(差为0)就会出问题。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;

#define MAX_N 1000

int d[MAX_N+10], p[MAX_N+10], he[MAX_N+10], cha[MAX_N+10],/**he cha储存的是每一个人的*/
    dp[MAX_N+10][MAX_N+10], path[MAX_N+10][MAX_N+10];

bool check(int i, int j, int k)
{
    while(i > 0 && path[i][j] != k)
    {
        j -= cha[path[i][j]];
        i--;
    }
    return i?false:true;
}


int main()
{
    int n, m, t = 0;
    while(cin >> n >> m)
    {
        if(n == 0 && m == 0)
            break;

        t++;
        int flag = 0;
        for(int i = 1;i <= n;i++)
        {
            cin >> p[i] >> d[i];

            he[i] = p[i]+d[i];
            cha[i] = d[i]-p[i];

            //cout << "i=" << i << " cha[i]=" << cha[i] << " he[i]=" << he[i] << endl;
        }

        //cout << "input finished" << endl;


        //attention path[][]也要每轮维护初始值0
        memset(path, 0, sizeof(path));
        memset(dp, -1, sizeof(dp));
        //dp[i][j] 挑选i个人 差为j时和的最大值

        dp[0][400] = 0;
        for(int i = 1;i <= m;i++)
        {
            for(int j = 0;j <= 800;j++)
            {
                if(dp[i-1][j] >= 0)//上一状态存在
                {
                    //cout << "dp[i-1][j]=" << "dp["  <<i-1 <<"]["<<j<<"]=" << dp[i-1][j] << endl;
                    for(int k = 1;k <= n;k++)
                    {
                        if(dp[i][j+cha[k]] < dp[i-1][j]+he[k])
                        {
                            if(check(i-1, j, k))
                            {
                                dp[i][j+cha[k]] = dp[i-1][j]+he[k];
                                //cout << "dp[i][j+cha[k]]="<<"dp["<<i<<"]["<<j+cha[k]<<"]="<<dp[i][j+cha[k]]<<endl;
                                path[i][j+cha[k]] = k;

                                //cout << "get num="<< k << endl;
                                //cout << "now i =" << i <<endl;
                                //cout << "dp[i][j+cha[k]]=" <<dp[i][j+cha[k]] <<endl;
                                //cout << "j+cha[k]" << j <<" "<<cha[k]<<" "<< j+cha[k] << endl;
                            }
                        }
                    }
                }
            }
        }

        //cout << "dp finished" << endl;

        int pro = 0, def = 0;
        //cout << "vector" << endl;
        vector<int> ans;

        //cout << "loop" << endl;
        for(int i = 0;i <= 400;i++)
        {
            //cout << dp[m][i] <<endl;
            if(dp[m][400+i] >= 0 || dp[m][400-i] >= 0)
            {
                cout << "Jury #" << t << endl;

                int r = 0;
                if(dp[m][400+i] > dp[m][400-i])
                    r = 400+i;
                else
                    r = 400-i;

                //cout << r << endl;
                int tempm = m;

                pro = (dp[m][r] + r - 400) / 2;
                def = (dp[m][r] - r + 400) / 2;

                while(tempm > 0)
                {
                    ans.push_back(path[tempm][r]);

                    r -= cha[path[tempm][r]];
                    tempm--;
                }

                cout << "Best jury has value " << pro << " for prosecution and value " << def <<" for defence:" << endl;
                sort(ans.begin(), ans.end());

                for(vector<int>::iterator it = ans.begin();it != ans.end();it++)
                {
                    cout << " " << *it;
                }

                break;
            }

        }

        ans.clear();
        cout << endl << endl;

    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值