poj2976(二分求解0/1分数规划模型)

这是一个关于0/1分数规划的问题,通过二分搜索找到最大正确率。不能直接使用动态规划,因为数据规模可能导致超时。算法核心是检查是否存在一个子集,使得其正确率大于等于目标正确率。通过对每场考试的得分进行调整,并对调整后的值进行排序,选取最大的子集来判断可能性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
translation:
	给出n场考试,每场考试有总题量,和你答对的题量。现在要求你去掉一些考试项目,使得你的正确率能够达到最大是多少?
solution:
	0/1分数规划,二分解决
	赤裸裸的0/1分数规划,但是此题不能采用dp,因为a,b数据太大,超时。所以考虑采用二分来枚举可能的最大正确率。
	然后判断该次枚举的是否可能。这样就转化成了二分确定最大值的问题。现在怎么判断是个问题。因为不能直接用贪心法来
	根据单次考试的正确率来决策。这样样例中的0/1项在第一次就被筛了。因为总的正确率是根据总的题量和总的答对数来计算的
	单单根据一次考试是无法得到正确结果。所以考虑有一子集使得能够满足枚举的正确率mid。这样有sum(ai)/sum(bi) >= mid
	简单变换之后:sum(ai - mid * bi) >= 0。这样对每场考试就能产生一个衡量指标 ai - mid * bi。问题进一步转换成
	在众多考试项目中选择一个n-k子集,使得它们的衡量指标之和大于等于0.所以只要排序一下,然后从下标k开始知道末尾,相加起来的
	就是所能选出的最大衡量指标。这样就能进行判断了。
note:
	*:0/1分数规划的二分做法
	*:注意输出离小数最近的一个整数的做法。
date:
	2016.11.3
*/
#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
const int maxn = 1000 + 10;

struct Test
{
	int a, b;
} t[maxn];
int n, k, sum_up, sum_down;
double s[maxn];

bool check(double mid)
{
	for(int i = 0; i < n; i++)
		s[i] = (double)t[i].a - mid * t[i].b;
	sort(s, s + n);

	double res = 0.0;
	for(int i = k; i < n; i++)	res += s[i];
	return res >= 0;
}

int main()
{
	//freopen("in.txt", "r", stdin);
    while(~scanf("%d%d", &n, &k)){
		if(!n && !k)	break;
		sum_up = sum_down = 0;
		for(int i = 0; i < n; i++)	scanf("%d", &t[i].a);
		for(int i = 0; i < n; i++)	scanf("%d", &t[i].b);

		double pl = 0.0, pr = 1.0;
		for(int i = 0; i < 100; i++){
			double mid = (pl + pr) / 2.0;
			if(check(mid))	pl = mid;
			else			pr = mid;
		}
		printf("%d\n", (int)(pr*100 + 0.5));
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值