noip 1995 灯的排列问题 排列组合 DFS

题目描述

设在一排上有N个格子(N≤20),若在格子中放置有不同颜色的灯,每种灯的个数记为N1,N2,……Nk(k表示不同颜色灯的个数)。
   放灯时要遵守下列规则:
①同一种颜色的灯不能分开;
②不同颜色的灯之间至少要有一个空位置。
 例如:

N=8(格子数)
R=2(红灯数)

B=3(蓝灯数)

   放置的方法有:
      R-B顺序


      B-R顺序



    放置的总数为12种。
    程序要求:求排列总数。

输入格式


数据输入的方式为:
N
P1(颜色,为一个字母) N1(灯的数量)
P2 N2
……
Q(结束标记,Q本身不是灯的颜色)

 颜色和灯的数量之间由一个空格分隔。


输出

输出排列总数。
样例输入
8
R 2
B 3
Q

样例输出
12


题解: 

记录方案的dfs:http://www.cnblogs.com/qscqesze/p/4334157.html
注意同一颜色归到一起
dfs出一种颜色顺序下的所有顺序
再将它乘上N种颜色的排列数N!
即可得到总排列数。。。。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mem(a) memset(a,0,sizeof(a))
#define mp(x,y) make_pair(x,y)
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
inline ll read(){
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
//
const int maxn = 1e5+10;

int n,s,num,k;
char c;
struct node{
	char x;
	int y;
}q[maxn];

void dfs(int a,int b,int c){   //a表示已用颜色  b表示已放格子数  c表示是否要放空格  
	if(a==num && b==n){
		k++;  //同一颜色顺序下排序数  
		return ;
	}
	if(b > n) return ;
	if(!c) dfs(a+1,b+q[a].y,1);
	dfs(a,b+1,0);
}

int main(){
	n = read();
	while(cin>>c, c!='Q'){
		int b = read();
		s += b;
		bool f = 0;
		for(int i=0; i<num; i++){
			if(q[i].x == c){
				q[i].y += b;
				f = 1;
			}
		}
		if(!f){
			q[num].x = c;
			q[num++].y += b;
		}
	}
	int per=1;
	for(int i=1; i<=num; i++)
		per = per*i;
	if(n - (s+num-1) <= 0) {  //格子不够 
		puts("0");
		return 0;
	}else{
		dfs(0,0,0);
		cout << per*k << endl;
	}

    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值