kuangbin题单 简单DP 背包问题 记录路径 Jury Compromise POJ1015/UVA 323

打卡 day 6
昨天写小白月赛,今天又在写大创的申报书,鸽了一天。
先写个题面:n个民众选m个组成陪审团,每个民众对于控方和辩方都有一个喜好值,选的这m个民众,对两方的每方喜好值之和的差的绝对值最小,如果有差一样小的,就选和最大的。
其实昨天是把这题开了的,但是没想出来怎么做,看了大佬的代码也不是很懂具体的思想。今天抽时间来好好想想。
第一个点就是 fix ,修正值,就是每一个人的两个喜好值差值最大是20,然后一共m个人,我们从20*m的位置作为起点,这样差值是负值就避免了数组越界,[0,200)我们定为负值,[200,400]我们定为正值。
第二步就是开始传递,三重循环,找出各种人数在各个评价差上的最大总评价之和。m相当于背包的容量,每一次进入一个重量为1的物品,k就是j选择的d-p的差值。(k=d-p)
记录路径就是把每一位选择的民众用vector存储在d-p这个差值的位置。
只有m用完,d-p的最小值才能确定。
第三步就是找,从中间开始找,找到差值最小的位置,记录下标。然后根据 |d-p| 的值计算出d与p的值:
d = ( ∣ d − p ∣ + ( d + p ) ∣ d=(|d-p|+(d+p)| d=(dp+(d+p) p = ( ( d + p ) − ∣ d − p ∣ ) p=((d+p)-|d-p|) p=((d+p)dp)

我模了
AC代码:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=205;
struct node{
    int p;
    int d;
    int add;
    int sub;
}a[maxn];
int t;
int dp[25][maxn<<2];
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)){
        if(n==0&&m==0) break;
        vector<int> path[25][maxn<<2];
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a[i].p,&a[i].d);
            a[i].add=a[i].p+a[i].d;
            a[i].sub=a[i].d-a[i].p;
        }
        memset(dp,-1,sizeof(dp));
        int fix=20*m;//修正值
        dp[0][fix]=0;
        for(int i=1;i<=n;i++){
            for(int j=m-1;j>=0;j--){
                for(int k=0;k<=2*fix;k++){
                    if(dp[j][k]>=0){
                        if(dp[j][k]+a[i].add>dp[j+1][k+a[i].sub]){
                            dp[j+1][k+a[i].sub]=dp[j][k]+a[i].add;
                            path[j+1][k+a[i].sub]=path[j][k];
                            path[j+1][k+a[i].sub].push_back(i);
                        }
                    }
                }
            }
        }
        int ans;
        for(int i=0;i<=fix;i++){
            if(dp[m][fix-i]>=0||dp[m][fix+i]>=0){
                ans=i;
                break;
            }
        }
        int res=dp[m][fix-ans]>=dp[m][fix+ans]?fix-ans:fix+ans;
        int d=(res-fix+dp[m][res])/2;
        int p=(dp[m][res]-res+fix)/2;
        int len=path[m][res].size();
        printf("Jury #%d\n",++t);
		printf("Best jury has value %d for prosecution and value %d for defence: \n",p,d);
		for(int i=0;i<len;i++){
			printf("%d ",path[m][res][i]);
		}
		printf("\n");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值