#POJ1173#Bar Code

30 篇文章 0 订阅
14 篇文章 0 订阅

【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;
	}
}



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值