POJ 1742 Coins

本文介绍了一种优化的多重背包问题解决方法,通过布尔值dp数组判断能否构成特定价值,并使用cnt数组记录构成该价值所需的硬币数量,实现高效求解。
/*	2016年8月2日19:50:12  
有 n 种硬币,每种硬币有 c 个,问这 n 种硬币能组成 1-m 的多少个价值。

直接用多重背包会T
 	多重背包另一种做法 
布尔值 dp[i] 表示能否组成i价值 
	cnt[i] 表示组成i价值 要使用多少个 当前的硬币 
详见代码 
*/

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define pi acos(-1)
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 5;

bool dp[maxn];
int A[105], C[105];
int cnt[maxn];
int n, m;
int main(void)
{
//	freopen("C:\\Users\\wave\\Desktop\\NULL.exe\\NULL\\in.txt","r", stdin);
    int i, j, ans;
    while (~scanf("%d %d", &n, &m) && (n||m))
    {
        for (i = 1; i <= n; i++)
            scanf("%d", &A[i]);
        for (i = 1; i <= n; i++)
            scanf("%d", &C[i]);
        memset(dp, false, sizeof(dp));
        dp[0] = true;
        ans = 0;
        for (i = 1; i <= n; i++){
            memset(cnt, 0, sizeof(cnt));
            for (j = A[i]; j <= m; j++){
                if (!dp[j] && dp[j - A[i]] && cnt[j - A[i]] < C[i]){
                    dp[j] = true;
                    cnt[j] = cnt[j - A[i]] + 1;
                    ans++;
                }
            }
        }
        cout << ans << endl;
    }

    return 0;
}

### 关于POJ 1742 编程问题描述与解决方案 #### 题目概述 题目编号为 **POJ 1742** 的问题是关于计算几何中的最小圆覆盖问题。该问题的核心在于给定一组平面上的点集,求能够完全覆盖这些点的最小半径圆的位置及其大小。 此问题通常采用随机增量法解决,其时间复杂度接近 \(O(n)\),是一种高效的算法实现方式[^6]。 --- #### 输入输出说明 - **输入**: 多组测试数据,每组的第一行为整数 \(N\) (\(1 \leq N \leq 100\)) 表示点的数量;随后有 \(N\) 行,每一行有两个浮点数表示平面坐标系上的点位置 \(x_i, y_i\)。 - **输出**: 对于每组测试数据,输出一个实数表示能覆盖所有点的最小圆的半径 \(R\),保留两位小数。 --- #### 解决方案思路 为了高效解决问题,可以利用随机化方法优化暴力解法的时间性能: 1. 初始化:假设第一个点作为初始圆心,并设置半径为零; 2. 迭代更新:依次加入新的点到当前已构建的圆中,若新点位于圆外,则调整圆使其包含新增加的点; 3. 调整策略:当发现某一点无法被现有圆所覆盖时,重新以这一点为基础构造一个新的圆并重复上述过程直到完成整个集合处理。 以下是基于C++语言的具体实现代码片段: ```cpp #include <bits/stdc++.h> using namespace std; struct Point { double x, y; }; double dist(const Point &a, const Point &b){ return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } Point getCircleCenter(double bx,double by,double cx,double cy){ double B = bx*bx+by*by,C=cx*cx+cy*cy,D=bx*cy-by*cx; return { (by*cy-cy*by)/D , ((bx+by)*(cx+cy)-(B-C)/(2*D))/(2*(bx-cx)) }; } void minCoveringCircle(int n, vector<Point> points){ random_shuffle(points.begin(),points.end()); Point c={0,0}; int r=0; for(int i=0;i<n;i++)if(dist(c,points[i])>r+.5){ c=points[i]; r=0; for(int j=0;j<i;j++)if(dist(c,points[j])>(r+=dist(c,points[j]))+.5){ c=(Point){(c.x+points[j].x)/2,(c.y+points[j].y)/2}; r=dist(c,points[j]); for(int k=0;k<j;k++)if(dist(c,points[k])>(r=dist(getCircleCenter( points[i].x-points[j].x, points[i].y-points[j].y, points[i].x-points[k].x, points[i].y-points[k].y))+dist(points[i],getCircleCenter( points[i].x-points[j].x, points[i].y-points[j].y, points[i].x-points[k].x, points[i].y-points[k].y))) ){ c=getCircleCenter(points[i].x-points[j].x,points[i].y-points[j].y,points[i].x-points[k].x,points[i].y-points[k].y); c.x += points[i].x; c.y += points[i].y; } } } printf("%.2f\n",r); } ``` --- #### 注意事项 - 数据范围较大情况下需注意精度损失问题,在必要时候可适当增加额外判断条件来减少误差影响。 - 使用 `random_shuffle` 函数前应引入 `<algorithm>` 库支持,并确保编译器版本兼容 C++11 或更高标准。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值