题目:Stringsobits
Kim Schrijvers
Consider an ordered set S of strings of N (1 <= N <= 31) bits. Bits, of course, are either 0 or 1.
This set of strings is interesting because it is ordered and contains all possible strings of length N that have L (1 <= L <= N) or fewer bits that are `1'.
Your task is to read a number I (1 <= I <= sizeof(S)) from the input and print the Ith element of the ordered set for N bits with no more than L bits that are `1'.
PROGRAM NAME: kimbits
INPUT FORMAT
A single line with three space separated integers: N, L, and I.
SAMPLE INPUT (file kimbits.in)
5 3 19
OUTPUT FORMAT
A single line containing the integer that represents the Ith element from the order set, as described.
SAMPLE OUTPUT (file kimbits.out)
10011
分析:
最先想到的是采用filtering,即从数字0 - (2^N-1), 依次判断该数字转换成位串后是否满足条件----含1的个数小于等于L。直到找到第I个满足该条件的数。
但是这样的时间复杂度为 O(N * 2^N), 题目中N最大为31,估计运行时间要超过1s。
为了加快速度,可采用generating,即直接去生成想要的那个位串。方法是先确定第一位是0还是1, 然后转化为子问题进行递归。 其实可以计算出第一位
是0时(或1时)有多少个满足条件的位串(求组合数)。求出来之后就直到第一位是0还是1了,然后进行递归。
代码:C++
/*
ID: randyji1
PROG: kimbits
LANG: C++
*/
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cassert>
using namespace std;
ifstream fin("kimbits.in");
ofstream fout("kimbits.out");
int strLen, maxNOfOnes;
unsigned long ith;
void getInput() {
fin >> strLen >> maxNOfOnes >> ith;
}
unsigned long getComb(int n, int m) {
m = min(m, n-m);
double result = 1;
for(int i = n-m+1; i <= n; i++)
result *= i;
for(int j = 1; j <= m; j++)
result /= j;
return result;
}
unsigned long getCount(int n, int maxNOfOnes) {
unsigned long result = 0;
int upper = min(n, maxNOfOnes);
for(int i = 0; i <= upper; i++) {
result += getComb(n, i);
}
return result;
}
void getFirstBit(int strLen, int maxNOfOnes, unsigned long ith) {
//cout << strLen << " " << maxNOfOnes << " " << ith << endl;
if(strLen == 1) {
assert(ith == 1 || ith == 2);
if(ith == 1) {
fout << '0' << endl;
} else {
assert(maxNOfOnes >= 1);
fout << '1' << endl;
}
return;
}
if(maxNOfOnes == 0) {
while(strLen--) {
fout << '0';
}
fout << endl;
return;
}
//计算以0开头的合法的有多少个
unsigned long count = getCount(strLen-1, maxNOfOnes);
if(ith <= count) {
fout << '0';
getFirstBit(strLen-1, maxNOfOnes, ith);
} else {
fout << '1';
getFirstBit(strLen-1, maxNOfOnes-1, ith-count);
}
}
int main() {
assert(fin && fout);
getInput();
getFirstBit(strLen, maxNOfOnes, ith);
return 0;
}
注:C++没有求组合数的标准库(还是Matlab方便啊)。我自己写了一个,采用了最笨的方法,直接算,注意可能溢出。官方答案中采用了dynamic programming 来求。