概述
点击打开题目链接
多数据集,每个数据集给出不超过35个数,求其中非空子集使得该子集数字和的绝对值最小。
如果有多个这样的子集,取元素数目最少的。
最后输出该子集中数字的和的绝对值,以及子集所含元素数目。
35个数,容易想到折半,对半分开搜索,这样的话对于某一半的序列单纯枚举各数选与不选,差不多
就是2^17种,复杂度显然可以接受。
这道题思路就是前一半先搜完(各个元素枚举选与不选两种状态),然后搜到的各个非空子集可得到
sum,val,num这三个属性,分别表示其中元素和,元素和的绝对值,以及元素数目。不妨放到容器里存起来
然后后面一半再搜索,同样三种属性,不妨记为sum',val',num'。这里使sum'+sum绝对值最小,即要使sum最接近
-sum',这个可以用二分来实现。寻找到这样的sum后,相应的num也可以取出(我是用HashMap容器,这样两
者就直接映射起来了)。然后,总的子集元素数目即num'+num。这样处理,比较,更新答案。
上面的是主要的思路。其次,还有Java各容器的知识、应用,具体代码如下:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.StringTokenizer;
import java.util.TreeSet;
class Reader {
static BufferedReader reader;
static StringTokenizer tokenizer;
static void init(InputStream input) {
reader = new BufferedReader(new InputStreamReader(input));
tokenizer = new StringTokenizer("");
}
static String next() throws IOException {
while (!tokenizer.hasMoreTokens()) {
tokenizer = new StringTokenizer(reader.readLine());
}
return tokenizer.nextToken();
}
static int nextInt() throws IOException {
return Integer.parseInt(next());
}
static long nextLong() throws IOException {
return Long.parseLong(next());
}
}
public class Main {
/**
* @param args
*/
static int n, len1, len2, anum, v, nnum, cnt, l, r, mid, fnum;
static long ans, sum, val, val1, val2;
static int num1, num2;
static long arr[], brr[], crr[], nownum[];
static HashMap<Long, Integer> hashMap;
static TreeSet<Long> treeSet;
private static void dfs1(int nown, int num) {
if (nown == len1 + 1) {
if (num == 0)
return;
val = Math.abs(sum);
treeSet.add(sum);
if ((val < ans) || (ans == val) && (num < anum)) {
ans = val;
anum = num;
}
if (!hashMap.containsKey(sum))
hashMap.put(sum, num);
else {
v = hashMap.get(sum);
if (v > num) {
v = num;
hashMap.put(sum, v);
}
}
return;
}
dfs1(nown + 1, num);
sum += brr[nown];
dfs1(nown + 1, num + 1);
sum -= brr[nown];
}
private static void dfs2(int nown, int num) {
if (nown == len2 + 1) {
if (num == 0)
return;
fnum = find(-sum);
val1 = Math.abs(sum + nownum[fnum - 1]);
num1 = num + hashMap.get(nownum[fnum - 1]);
if ((val1 < ans) || (ans == val1) && (num1 < anum)) {
ans = val1;
anum = num1;
}
val2 = Math.abs(sum + nownum[fnum]);
num2 = num + hashMap.get(nownum[fnum]);
if ((val2 < ans) || (ans == val2) && (num2 < anum)) {
ans = val2;
anum = num2;
}
return;
}
dfs2(nown + 1, num);
sum += crr[nown];
dfs2(nown + 1, num + 1);
sum -= crr[nown];
}
private static int find(long num) {
l = 0;
r = nnum;
while (r - l > 1) {
mid = (l + r) / 2;
if (nownum[mid] <= num)
l = mid;
else
r = mid;
}
return r;
}
private static void deal() {
if (n == 1) {
System.out.println(Math.abs(arr[1]) + " 1");
return;
}
len1 = n / 2;
brr = new long[len1 + 1];
for (int i = 1; i <= len1; i++)
brr[i] = arr[i];
len2 = n - len1;
crr = new long[len2 + 1];
for (int i = 1; i <= len2; i++)
crr[i] = arr[len1 + i];
ans = Math.abs(arr[1]);
anum = 1;
sum = 0;
hashMap = new HashMap<Long, Integer>();
treeSet = new TreeSet<Long>();
dfs1(1, 0);
treeSet.add((long) 0);
hashMap.put((long) 0, 0);
nnum = treeSet.size();
nownum = new long[nnum + 1];
Iterator<Long> iter = treeSet.iterator();
cnt = 0;
while (iter.hasNext()) {
cnt++;
nownum[cnt] = iter.next();
}
dfs2(1, 0);
System.out.println(ans + " " + anum);
}
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
Reader.init(System.in);
n = Reader.nextInt();
while (n != 0) {
arr = new long[n + 1];
for (int i = 1; i <= n; i++)
arr[i] = Reader.nextLong();
deal();
n = Reader.nextInt();
}
}
}
最后
以上就是顺心香氛为你收集整理的poj3977(折半搜索)的全部内容,希望文章能够帮你解决poj3977(折半搜索)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复