Online JudgeProblem SetAuthorsOnline ContestsUser
Web Board
Home Page
F.A.Qs
Statistical Charts
Problems
Submit Problem
Online Status
Prob.ID:
Register
Update your info
Authors ranklist
Current Contest
Past Contests
Scheduled Contests
Award Contest
User ID:
Password:
  Register

贴Java代码。 半枚举+二分,带注释

Posted by haqishen at 2015-01-18 10:24:05 on Problem 3977 and last updated at 2015-01-18 10:28:15
// 如果是n个值进行枚举的话计算量是O(2^n),绝壁hold不住
// 所以把这些值分成两半,分别枚举,然后在组合这两个数组的时候用二分法避免了全列举。
// 当时做这道题目的时候写到一半发现不太对头,所以大改过(只比重写稍微轻松了一点点)所以代码看起来比较蛋疼且冗余。。。
//A了就懒得改了。嫌麻烦的只看注释吧2333
import java.io.*;
import java.util.*;
public class Main{

	static int N;

//      记录输入的数字
	static long nums[];
//      这两个动态数组分别记录分成两半后各自枚举的所有情况
	static ArrayList<subset> ssL = new ArrayList<subset>();
	static ArrayList<subset> ssR = new ArrayList<subset>();
//      这两个数组用于枚举(取不取当前数字?取的话设为1,不取设为0)
	static int[] iruL;
	static int[] iruR;

//	最小的绝对值
	static long ans;
//	最小的元素个数
	static int ansc;
	
//	下面2个函数把N个值分成两半然后分别枚举,各自最多为2^17,2^18种情况
	static void generate_subsetL(int index){
		if(index == N/2){
			long sum = 0;
			int count = 0;
			
			for(int i = 0; i < iruL.length; i++){
				if(iruL[i] == 1){
					count++;
					sum += nums[i];
				}
			}
			ssL.add(new subset(sum,count));
			return;
		}
		
//              用递归进行枚举
		for(int i = 0; i < 2; i++){			
			iruL[index] = i;			
			generate_subsetL(index+1);
		}
	}
	
	static void generate_subsetR(int index){
		if(index == N-N/2){
			long sum = 0;
			int count = 0;			
			for(int i = 0; i < iruR.length; i++){
				if(iruR[i] == 1){
					count++;
					sum += nums[i+N/2];
				}
			}
			ssR.add(new subset(sum,count));
			return;
		}
		
		for(int i = 0; i < 2; i++){	
			iruR[index] = i;
			generate_subsetR(index+1);
		}
	}

//      组合两个数组。因为ssL数组规模小于等于ssR,所以对ssL进行了排序
//      然后循环ssR中每个元素,二分ssL
	private static void solve() {

//		循环ssR的所有元素
		for(int q = 0; q < ssR.size(); q++){
			long sum = ssR.get(q).sum;
			int count = ssR.get(q).count;
			
//			用二分法逼近答案,因为可能会有多解的情况
//			所以需要进行两次,第一次寻找最接近0的负值,第二次寻找最接近0的正值。
//			然后扫描这两者之间的所有元素,找出sum最小,且count最小的组合
//			先找最接近0的负值,二分后取左边界
			int l = 0;
			int r = ssL.size();
			while(r-l>1){
				int m = (l+r)/2;
				if(ssL.get(m).sum + sum >=0){
					r = m;
				}else{
					l = m;
				}
			}
			int L = l;		
//			然后找最接近0的正值,二分后取右边界
			l = -1;
			r = ssL.size()-1;
			while(r-l>1){
				int m = (l+r)/2;
				if(ssL.get(m).sum + sum >0){
					r = m;
				}else{
					l = m;
				}
			}
			int R = r;		
//			扫描L到R中所有情况,与ans对比
//			L到R最少1种情况,最多13w种,不过只要出现ans=0,ansc=1就可以直接输出了。不可能出现要扫那么多情况的情况。
			for(int i = L; i <= R; i++){
				long tempsum = Math.abs(ssL.get(i).sum + sum);
				int tempcount = ssL.get(i).count + count;

//                              排除掉空集的情况
				if (tempcount == 0) continue;

				if(tempsum < ans){
					ans = tempsum;
					ansc = tempcount;
				}
				else if(tempsum == ans & tempcount < ansc){
					ansc = tempcount;
				}
				
				if(ans == 0 & ansc == 1)
					return;				
			}
		}		
	}
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		while(true){
			N = new Integer(br.readLine());
			if(N==0) break;
			
			nums = new long[N];
			iruL = new int[N/2];
			iruR = new int[N-N/2];
			ans = 1000000000000001l;
			ansc = 36;
			
			String input[] = br.readLine().split("\\s");
			for(int i = 0; i < N; i++){
				nums[i] = new Long(input[i]);
			}
			
//                      分成两半后分别枚举
			ssL.clear();
			ssR.clear();
			generate_subsetL(0);
			generate_subsetR(0);
			
//                      因为ssL数组规模小于等于ssR,所以对ssL进行了排序
			Collections.sort(ssL);
			
			solve();
			
			System.out.println(ans+" "+ansc);
		}
	}
}

//子集。变量是sum:该子集的元素和,count:该子集的元素个数
class subset implements Comparable<subset>{
	long sum;
	int count;
	subset(long sum, int count){
		this.sum = sum;
		this.count = count;
	}
	public int compareTo(subset o) {
		if(this.sum - o.sum < 0)
			return -1;
		else
			return 1;
	}
}

Followed by:

Post your reply here:
User ID:
Password:
Title:

Content:

Home Page   Go Back  To top


All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator