Stringsobits

题意:有序集合S中的元素都为N位的二进制数,这个集合S中的二进制数最多只有L个1,输出这个集合中第I个元素的二进制表示方法


解题思路

  1. DP问题,设f[i][j] = k,代表最多有j位为1的i位二进制数集合的大小为k。那么这个集合中的二进制数可以分为最高位为0和为1这两类,所以f[i][j] = f[i-1][j] + f[i-1][j-1]。
  2. 边界情况f[i][0] = 1,f[0][j] = 1。
  3. 两重循环i, j可以计算出矩阵f[i][j]。
  4. 下面计算集合中第I个元素的二进制表示,类似与二分查找。
  5. 初始化最高位为0的集合大小为left = f[N-1][L],最高位为1的集合大小为right = f[N-1][L-1]。如果L == 0,right = 0。
  6. 如果I <= left,那么第I个数最高位为0,如果I > left,那么第I个数的最高位为1。
  7. 如果此时最高位为0,那么N = N -1,如果此时最高位为1,那么N = N -1,L = L - 1, I = I - left。
  8. 递归循环5~7,直到N-1 < 0。在此过程中可以得到各个位置的数字。

代码

/*
ID: zc.rene1
LANG: C
PROG: kimbits
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main(void)
{
    FILE *fin, *fout;
    int N, L;
    unsigned long I;
    int **f;
    int i, j, left, right;

    fin = fopen("kimbits.in", "r");
    fout = fopen("kimbits.out", "w");

    fscanf(fin, "%d %d %lu", &N, &L, &I);
    
    f = (int **)malloc((N+1)*sizeof(int *));
    for (i=0; i<(N+1); i++)
    {
	f[i] = (int *)malloc((L+1)*sizeof(int));
	memset(f[i], 0, (L+1)*sizeof(int));
    }

    for (i=0; i<(N+1); i++)
    {
	f[i][0] = 1;
    }

    for (j=0; j<(L+1); j++)
    {
	f[0][j] = 1;
    }

    for (i=1; i<=N; i++)
    {
	for (j=1; j<=L; j++)
	{
	    f[i][j] = f[i-1][j] + f[i-1][j-1];
	}
    }

    while (1)
    {
	if ((N - 1) < 0)
	{
	    break;
	}
	left = f[N-1][L];
	if (L == 0)
	{
	    right = 0;
	}
	else
	{
	    right = f[N-1][L-1];
	}

	if (I <= left)
	{
	    N = N - 1;
	    fprintf(fout, "0");
	}
	else
	{
	    N = N - 1;
	    L = L - 1;
	    I = I - left;
	    fprintf(fout, "1");
	}
    }
    fprintf(fout, "\n");

    return 0;
}



































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值