在一个银行的大厅里有30个自动柜员机,编号分别为0..29,每个会员顾客都能通过这些柜员机提取10^9 ducats(一种早期的流通硬币单位)的借款业务,但必须在一个星期内还是通过这些柜员机完成还款业务。这种柜员机很特别,每个柜员机只能完成一种简单的动作:供客户提取固定数目的现金或接受客户固定数目的还款。第i个柜员机只能提供2^i ducats的借款业务,如果i是偶数的话;而如果i是奇数的话,则第i个柜员机只能提供2^i ducats的还款业务。
现在,如果有一个客户想要用这些柜员机借一定数目的钱,但是每个柜员机都只能使用一次,那么,他该使用哪些柜员机呢?
一个星期内还款时,他又该使用哪些柜员机呢?
比如,他要借7 ducats,则他会从4号柜员机拿到16 ducats,从0号柜员机拿到1 ducats,再到3号柜员机还掉8 ducats,到1号柜员机还掉2 ducats。
一个星期内还款时,他会到3号柜员机先还掉8 ducats,再到0号柜员机拿到1 ducats。
请你编写一个程序,当一个客户借款,告诉他该使用哪些柜员机,以后还款时又该使用哪些柜员机。
Input
第一行为整数N(N<=1000),表示客户的数目。下面有N行,每行为一个正整数,表示每个客户要借多少钱。注意:每个客户最多能借10^9 ducats。
Output
共2N行,第2i-1行表示客户i借款时该使用哪些柜员机,第2i行表示客户i还款时该使用哪些柜员机(1<=i<=N),每行都要求按柜员机编号从大到小输出,每个编号之间用1个空格隔开。
如果业务无法成交,则输出NIE。
Sample Input
2
7
385171980
Sample Output
4 3 1 0
3 0
NIE
29 28 27 24 20 19 18 17 16 15 14 9 5 4 2
这是今天做到的非常有趣的一道题目,方法很多。首先我们肯定会联想到普通二进制的运算,因为普通的二进制可以由某一位一下子确定下来,比如2^4次 不会由其他位上的选择影响到,但是这道题目当中2^4可能是2^5-2^4,所以一下子比较难想出来。
第一种方法,从低位开始看,如果总数模2为奇数,那么后面的数不论怎么搞处理出来必定是2的倍数,那么我们就可以说不管这位是加还是减,那么我们肯定要选的,否则这位现在不处理掉,将来肯定处理不掉,这样就抛弃了正负的影响,可以直接得出结果。
#include<stdio.h>
#include<iostream>
using namespace std;
int ans[40],ji;
void Ans(){
cout << ans[ji-1];
for(int i = ji-2; i >= 0;i--)
cout << " " << ans[i];
cout << endl;
}
void cal(int n){
ji = 0;
for(int i = 0; i < 30;i++) {
int tem = n%2;
if(0 != tem) {
ans[ji] = i;
ji ++;
if(0 == i%2)
n++;
else
n--;
}
n /= 2;
}
if(0 == n)
Ans();
else
cout << "NIE" << endl;
}
int main(){
int cas;
int n;
cin >> cas;
for(int i = 0 ;i < cas;i ++) {
cin >> n;
cal(-n);
cal(n);
}
return 0;
}
第二种方法 非常巧妙,假设我们要得到X元,那么我们就先将左右都能得到的都先拿到,假设得到了Y元,那么我们就要舍弃Y-X元,那么现在仅有一种选择,就是在不用的位上退掉多少钱,那么就是只要将这个数字直接化成一个二进制表示就可以了 代表了选择情况。
第三种情况,搜索状态,有30种物品,那么我们总共的状态数有2^30之多,如果去搜索每个状态肯定是不行的,我们这里就考虑到每出现一个物品,总状态数就会呈指数增长,所以我们这里将所有状态分成两堆,每对15个, 2^15状态,对于第一堆中的每个状态,在第二个状态中做二分搜索,或者直接开哈希表哈希。就是15*2^15状态,很小。
引用风神的话说就是这样的。
二分状态搜索
多半应用于背包的搜索,就是给你n<=30个物品,每个物品有一定的价值(Value<=10^9),问你将其分成两堆,使得两堆的总价值和差值最小是多少.
如果我们直接dfs搜索的话,复杂度会达到O(2^n).极限复杂度就是 2^30 !!!
我们可以先记录sum为所有物品的价值总和,然后先将前15个物品的所有组合状态用一个hash[state]记录下来,然后按价值排序.
再对后15个物品枚举组合状态,记其组合的价值为Val,那么我们在hash[]中二分查找一个状态state,使得Val+hash[state]最接近sum/2(就是总价值的一半)...然后最小差值就在 O( (2^15) * log2(2^15) ) + O( (2^15)*log2(2^15) ) [前15个状态排序+后15个状态二分的复杂度] 的时间内完美解决了...