Subset POJ - 3977(折半枚举+二分查找)

本文针对给定整数集合寻找子集使元素和的绝对值最小的问题,提出了一种通过分治并结合二分查找技术的有效算法。该算法能够显著减少搜索空间,实现高效求解。

题目来源:Subset

Description

Given a list of N integers with absolute values no larger than 1015, find a non empty subset of these numbers which minimizes the absolute value of the sum of its elements. In case there are multiple subsets, choose the one with fewer elements.

Input

The input contains multiple data sets, the first line of each data set contains N <= 35, the number of elements, the next line contains N numbers no larger than 1015 in absolute value and separated by a single space. The input is terminated with N = 0
Output

For each data set in the input print two integers, the minimum absolute sum and the number of elements in the optimal subset.

Sample Input

1
10
3
20 100 -100
0

Sample Output

10 1
0 2

题意

给定n个数,求这n个数所构成的集合的某个子集,使得这个子集中所有数和的绝对值最小,输出和的绝对值以及集合中数的个数。

思路

n是小于35的,直接枚举集合复杂度为2n,超时。可以枚举前n/2个数的集合,然后枚举后n/2个数的集合再在前面的集合中二分查找,这样复杂度为2(n/2) log(n/2)。

代码

#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
inline long long Abs(long long x)
{
    return x > 0 ? x : -x;
}
int n;
long long a[40];
int main()
{
    while (cin >> n)
    {
        if (n == 0)
            break;
        for (int i = 1; i <= n; ++i)
            cin >> a[i];
        map<long long, int>mmp;
        long long ans = Abs(a[1]);
        int len = n;
        for (int i = 1; i < (1 << (n / 2)); ++i)
        {
            long long sum = 0;
            int j = i, cnt = 0, pos = 1;
            while (j && pos <= n / 2)
            {
                if (j & 1)
                {
                    sum += a[pos];
                    cnt++;
                }
                j >>= 1;
                pos++;
            }
            if (Abs(sum) < ans)
            {
                ans = Abs(sum);
                len = cnt;
            }
            else if (Abs(sum) == ans)
            {
                len = min(len, cnt);
            }

            if (mmp[sum])
                mmp[sum] = min(mmp[sum], cnt);
            else
                mmp[sum] = cnt;
        }
        for (int i = 1; i < (1 << (n - n / 2)); ++i)
        {
            long long sum = 0;
            int cnt = 0, pos = 1, j = i;
            while (j && pos + n / 2 <= n)
            {
                if (j & 1)
                {
                    sum += a[pos + n / 2];
                    cnt++;
                }
                j >>= 1;
                pos++;
            }
            
            if (Abs(sum) < ans)
            {
                ans = Abs(sum);
                len = cnt;
            }
            else if (Abs(sum) == ans)
            {
                len = min(len, cnt);
            }
            map<long long, int>::iterator it = mmp.lower_bound(-sum);
            if (it != mmp.end())
            {
                if (Abs(sum + it->first) < ans)
                {
                    ans = Abs(sum + it->first);
                    len = cnt + it->second;
                }
                else if (Abs(sum + it->first) == ans)
                {
                    len = min(len, cnt + it->second);
                }
            }
            if (it != mmp.begin())
            {
                it--;
                if (Abs(sum + it->first) < ans)
                {
                    ans = Abs(sum + it->first);
                    len = cnt + it->second;
                }
                else if (Abs(sum + it->first) == ans)
                {
                    len = min(len, cnt + it->second);
                }
            }
        }
        cout << Abs(ans) << ' ' << len << endl;
    }
    return 0;
}
### 使用K-means++算法对鸢尾花数据集进行分类 K-means++是一种改进版的K-means聚类算法,主要解决了传统K-means初始化质心随机选取可能导致收敛速度慢以及容易陷入局部最优的问题。通过更科学的方式选择初始质心,K-means++能够显著提高聚类效果和计算效率。 以下是基于Python实现K-means++对鸢尾花数据集进行分类的具体方法: #### 导入必要的库 为了加载数据并执行K-means++聚类操作,需导入以下常用库: ```python import numpy as np import pandas as pd from sklearn.cluster import KMeans from sklearn.datasets import load_iris import matplotlib.pyplot as plt ``` #### 加载鸢尾花数据集 利用`sklearn.datasets.load_iris()`可以直接获取鸢尾花数据集,该数据集中包含了三个类别(Setosa、Versicolor 和 Virginica),每种类别有50个样本[^3]。 ```python data = load_iris() X = data.data[:, [2, 3]] # 花瓣长度(petal length)和花瓣宽度(petal width) y_true = data.target # 真实标签用于后续验证 ``` #### 初始化K-means++模型 在创建K-means对象时,可以通过设置参数`init='k-means++'`来启用K-means++算法。此选项会自动优化初始质心的选择过程。 ```python model = KMeans(n_clusters=3, init='k-means++', random_state=42) model.fit(X) ``` #### 可视化聚类结果 绘制散点图展示不同簇之间的分布情况,并标注真实标签以便对比分析。 ```python plt.figure(figsize=(8, 6)) colors = ['red', 'blue', 'green'] for i in range(3): # 对应三种不同的类别 subset = X[model.labels_ == i] plt.scatter(subset[:, 0], subset[:, 1], s=50, c=colors[i], label=f'Cluster {i}') centroids = model.cluster_centers_ plt.scatter(centroids[:, 0], centroids[:, 1], marker='*', s=200, c='#ff7f0e', label='Centroids') plt.xlabel('Petal Length (cm)') plt.ylabel('Petal Width (cm)') plt.legend() plt.title('Iris Clustering using K-means++') plt.show() ``` 以上代码实现了完整的K-means++聚类流程,包括数据准备、建模训练到最终可视化呈现。相比传统的K-means方法,采用K-means++可以有效提升模型性能与稳定性[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值