UVA - 1228 Integer Transmission - Dynamic Programming Combinatorics (recursive)

problem

analysis

This problem looks very complicated, but the idea is very clear on the purple book, written in accordance with the above idea is relatively simple

The first is the issue that there is a transmission bit [1-d + 1] delay disrupt the order in which the same number of 0,1, can be regarded as 0 all predetermined according to the original order is received, the All 1 seen in accordance with, the provisions which put the original question becomes the order they are received two strings of numbers 0, 1 alternate interpolation , the difference between the number of 0,1 to within d of, so we can solve the biggest and greedy method minimum
assuming that the original 1-n-bit number, the transmission becomes [1, n + d] so long, but the actual time interval that does not exceed the number reaches n, we can remove the excess a predetermined delay, does not affect the results then the same time since the digital arrival may be arranged in any order, it may be time to reach some of the figures were combined, as shown in Figure 9-25 on purple book, summed up the rule is an arbitrary time k, which have been received rightmost bit who must without delay
following a state transition and state, a predetermined state D (i, j) is the number of i-th preceding integer 0 and j 1 are combined into one, the following will transfer only two ways, one is 0 followed by the addition proceeds to dp (i + 1, j) , the other Then add 1 is transferred to DP (i, j + 1), is somewhat similar to merge two arrays merge sort
is necessary to determine whether the condition when added, is between the two numbers (i + 1 or i and j and j + combinations of two ways 1) the transmission time interval is less than d
complexity of the overall time O ( n 2 ) O (n ^ 2)

note

Unsigned long long storage use state

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <vector>
#include <utility>
using namespace std;
const int maxn=70;
unsigned long long ans=0,n,d,k,maxv,minv,dp[maxn][maxn];  //long long会溢出
int kase=0,digit[maxn],digit0[maxn],digit1[maxn],n0,n1;

void dec2bin(unsigned long long t){
    for(int i=0;i<n;++i){
        digit[n-i-1]=t%2;
        t=t/2;
    }
}

void countDigit(){
    for(int i=0;i<n;++i){
        if(digit[i]==0){
            digit0[n0++]=i;
        }else{
            digit1[n1++]=i;
        }
    }
}

void greedy(){
    maxv=minv=0;
    int i=0,j=0;
    //反向计算二进制指数值的技巧
    while(i<n0 || j<n1){
        if(i<n0 && (j==n1 || digit1[j]+d>=digit0[i])){
            ++i;
            minv=2*minv;
        }
        else {
            ++j;
            minv=2*minv+1;
        }
    }
    i=j=0;
    while(i<n0 || j<n1){
        if(j<n1 && (i==n0 || digit0[i]+d>=digit1[j])){
            ++j;
            maxv=2*maxv+1;
        }
        else {
            ++i;
            maxv=2*maxv;
        }
    }
}

int main(void){
    while(cin>>n && n){
        cin>>d>>k;
        n0=n1=0;
//        memset(digit,-1,sizeof(digit));
        dec2bin(k);
        countDigit();
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;  //dp[0,0]代表空的序列
        //dp[i,j] 代表i个0和j个1,所以对应数组中序号要减少
        for(int i=0;i<=n0;++i){
            for(int j=0;j<=n1;++j){
                if(i<n0 && (j==n1 || digit1[j]+d>=digit0[i])) dp[i+1][j]+=dp[i][j];  //加入0
                if(j<n1 && (i==n0 || digit0[i]+d>=digit1[j])) dp[i][j+1]+=dp[i][j];  //加入1
            }
        }
        ans=dp[n0][n1];
        greedy();
        printf("Case %d:",++kase);
        cout<<" "<<ans<<" "<<minv<<" "<<maxv<<endl;
    }
}
Published 15 original articles · won praise 0 · Views 164

Guess you like

Origin blog.csdn.net/zpf1998/article/details/104051705