【POJ1173】条形码
时间限制: 1 Sec 内存限制: 128 MB题目描述
条形码如下图所示,由黑白两色构成,每种颜色分布一定的宽度。宽度是一个有上限的整数值。例如下图的条形码有4个条形,宽度分别是1,2,3,4,总宽度为:1+2+3+1 =7
定义BC(n,k,m) 表示有k个条形,每个条形的宽度不超过m,总宽度为n的条形码的总个数。例如BC(7,4,3)表示了如下所有的条形码:
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
其中1表示黑色,0表示白色。冒号前的数字表示了它的字典序号。上图中的条形码的序号为4。
你的任务是读入n, k, m,计算满足要求的条形码的总个数,以及读入若干个条形码,计算对应的字典序号。
输入
第1行:3个整数n,k,m(1 <= n,k,m <= 33)
第2行:1个整数s(0 <= s <= 100).
接下来s行,每行1个01串,表示一个条形码
输出
第1行:1个整数,表示满足要求的条形码的总个数
接下来s行,每行1个整数,表示对应条形码的字典序
样例输入
7 4 3
5
1001110
1110110
1001100
1001110
1000100
样例输出
16
4
15
3
4
0
第一问(组合数):
BC(n,k,m) 表示总宽度为n的条形码,有k个条形,每个条形的宽度不超过m的总个数。
->有N个不同的小球,对这些小球分K组,要求每一组中最多有m个盒小球
->有N个不同的小球,K个不同的盒子,每个盒子最多装m个球,至少装一个球,球必须用完
看上面对题目的第二步转换
“->有N个不同的小球,K个不同的盒子,每个盒子最多装m个球,至少装一个球,球必须用完”
定义F[ N , K ]表示总长度为N,每个条形的宽度不超过m,一共K个条形(有黑有白)的方案总数
考虑第N个小球放的位置
如果第N个小球单独占用一个盒子,那么前面N - 1个小球已经占用了K - 1个盒子,此种情况总方案为F[N- 1 , K - 1]
因为每个盒子最多装m个球
所以第K - 1个盒子在N - 1个球中最多可以放从第N - m个球到第N - 1个球
此时第K - 1个盒子里放了N - m - (N - 1) = m个球
对于当前第N球的位置,第K - 1个盒子,放入N - m - 1个球的状态是不合法的,
所以第N个小球单独占用第K个盒子的方案数为 (F[N - 1, K - 1] - F[N - m - 1 , K - 1])
如果第N个小球放在前面已经有小球的盒子里,那么前面N - 1个小球已经占用了K个盒子,此种情况总方案为F[N - 1, K]
综上: F[ N , K ] = F[N , K - 1] + (F[N - 1, K - 1] - F[N - m - 1 , K - 1])
第二问:(DP)
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
将二进制条形码转换方法来表示,方便比较先后顺序
将同一个色条的宽度作为当前色条的值,可以得到当前条形码是一个K位的数字编码
eg:
1001110 -> 1231
1110110 -> 3121
1001100 -> 1222
1001110 -> 1231
1000100 -> 1312
定义Dp[ i , j ]表示
以1101110 -> 2131,K=4,举例说明接下来的过程, 在此条形码前面的条形码有以下几种形态(转换后的编码)
//别忘记第一问求出来的F的定义
1 _ _ _ -> 剩下长度N=6,K=3-> F[6 , 3]=7
23_ _ ->剩下长度N=2,K=2 ->F[2 , 2]=2
22_ _ ->剩下长度N=3,K=2 ->F[3 , 2]=1
212_ ->.... ->F[2 , 1]=1
211_ ->.... ->F[3 , 1]=1
黑条1靠前越多越大,白条0靠前越多越小
#include<iostream>//F[N][K]=F[N-1][K]+F[N-1][K-1]-F[N-M-1][K-1]
#include<cstdio>
#include<cmath>
using namespace std;
int N,K,M,ans;
char S[35];
int F[35][35],len[35];
void Trans(){
int p=0;
for(int i=1; i<=K; ++i){
if(i&1)
while(S[++p]=='1')++len[i];
else while(S[++p]=='0')++len[i];
--p;
}
return ;
}
void Count_Code(){
ans=0;
int l=N;
for(int i=1; i<=K; ++i){
if(i&1){//黑色条
for(int j=1; j<len[i]; ++j)
if(l>=j) ans+=F[l-j][K-i];
}
else //白色条
for(int j=M;j>len[i]; --j)
if(l>=j) ans+=F[l-j][K-i];
l-=len[i];
}
return ;
}
int main(){
int s;
scanf("%d%d%d",&N,&K,&M);
F[0][0]=1;
for(int i=1; i<=N; ++i)
for(int j=1; j<=K; ++j){
F[i][j]=F[i-1][j]+F[i-1][j-1];
if(i-M-1>=0)
F[i][j]-=F[i-M-1][j-1];
}
printf("%d\n",F[N][K]);
scanf("%d",&s);
while(s){
--s;
scanf("%s",S+1);
Trans();
Count_Code();
printf("%d\n", ans);
for(int i=1; i<=K;++i)len[i]=0;
}
}