Bar Codes - POJ 1173 dp

本文探讨了特定条件下条形码符号的组合数量及排列问题,并提供了一种使用动态规划算法来解决该问题的方法。

Bar Codes
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 917 Accepted: 323

Description

A bar-code symbol consists of alternating dark and light bars, starting with a dark bar on the left. Each bar is a number of units wide. Figure 1 shows a bar-code symbol consisting of 4 bars that extend over 1+2+3+1=7 units. 
 
Figure 1: Bar-code symbol over 7 units (see top) with 4 bars (see bottom)


In general, the bar code BC(n,k,m) is the set of all symbols with k bars that together extend over exactly n units, each bar being at most m units wide. For instance, the symbol in Figure 1 belongs to BC(7,4,3) but not to BC(7,4,2). 
0: 1000100  |  8: 1100100

1: 1000110  |  9: 1100110

2: 1001000  | 10: 1101000

3: 1001100  | 11: 1101100

4: 1001110  | 12: 1101110

5: 1011000  | 13: 1110010

6: 1011100  | 14: 1110100

7: 1100010  | 15: 1110110

Figure 2: All symbols of BC(7,4,3)


Figure 2 shows all 16 symbols in BC(7,4,3). Each `1' represents a dark unit, each `0' a light unit. The symbols appear in lexicographic (dictionary) order. The number on the left of the colon (`:') is the rank of the symbol. The symbol in Figure 1 has rank 4 in BC(7,4,3). 

Input

Your program is to read from standard input. The first line contains the numbers n, k, and m (1 <= n,k,m <= 33). On the second line is a number s (0 <= s <= 100). The following s lines each contain some symbol in BC(n,k,m), represented by '0's and '1's as in Figure 2.

Output

Your program is to write to standard output. On the first line your program should write the total number of symbols in BC(n,k,m). On each of the s following lines, it should write the rank of the corresponding symbol in the input.

Sample Input

7 4 3
5
1001110
1110110
1001100
1001110
1000100

Sample Output

16
4
15
3
4
0

题意:有n的长度,k个木板,每个木板的长度最多为m,问有多少种组合方式,对于给定的组合是字典序的第多少个。

思路:用dp[i][j]表示后i个木板组成长度为j的有多少种情况。确定给定的组合是第几个的话,就从前往后数,奇数的木板,假如给定的长度为3,那么就答案就加上当它为1和2的时候后面的情况数,偶数的是长度从大到小加上它后面的情况。

AC代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll dp[40][40];
int num[40];
char s[110];
int n,k,m;
int main()
{
    int i,j,a,b,p,cas,pos,len;
    ll ans,ret;
    while(~scanf("%d%d%d",&n,&k,&m))
    {
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(i=1;i<=k;i++)
           for(j=1;j<=n;j++)
           {
               for(a=1;a<=m && j-a>=0;a++)
                  dp[i][j]+=dp[i-1][j-a];
           }
        ans=0;
        printf("%I64d\n",dp[k][n]);
        scanf("%d",&cas);
        while(cas--)
        {
            scanf("%s",s+1);
            pos=0;
            for(i=1;i<=k;i++)
            {
                pos++;
                num[i]=1;
                while(pos<n && s[pos]==s[pos+1])
                {
                    num[i]++;
                    pos++;
                }
            }
            len=n;
            ans=0;
            for(i=k;i>=1;i--)
            {
                p=k-i+1;
                if(p&1)
                  for(j=1;j<num[p] && len-j>0;j++)
                     ans+=dp[i-1][len-j];
                else
                  for(j=min(m,len);j>num[p];j--)
                     ans+=dp[i-1][len-j];
                len-=num[p];
            }
            printf("%I64d\n",ans);
        }
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值