头像

欢迎来到我的博客

分享题解与总结

剪邮票

题目:

屏幕截图 2026-03-02 082545

屏幕截图 2026-03-02 082600

核心:

排列+判断连通性

求排列的方法:

swap交换法

判断连通性:

(1)假设裁剪的部分为2,6,7,11,12,

将2作为起点加入队列 .

(2)从2开始,遍历四个方向:上下左右 .

如果下一位置的数在裁剪部分当中,

则加入队列,否则不加入队列.

(3)队列为空后,如果进入队列的元素总数为5,则这5个数是连通的

注意:

由于使用的是一维数组,如果是+1,-1得到下一个数的位置的话,需要额外判断是否跨行

屏幕截图 2026-03-02 094432

去重:

[1,2,3,4,5]与[2,1,3,4,5]两种排列:同一种裁剪

最后答案除以5!即可

代码:

#define M 12
int a[M]={1,2,3,4,5,6,7,8,9,10,11,12};
int cpy[M]={1,2,3,4,5,6,7,8,9,10,11,12};
int ans;

bool isIna(int idx)//判断该数在不在裁剪部分 
{
	for(int i=0;i<5;++i){//裁剪部分 存储在 a[0,4] 
		if(cpy[idx]==a[i])
			return true;
	}
	return false;
}

int gets()//get-start 获得剪下来的邮票 起始位置 
{
	for(int i=0;i<12;++i){
		if(a[0]==cpy[i])//a[0-4]:这次剪下来的邮票,比如[2,6,7,11,12]这五张
			return i;//找到[2]这张邮票的原始下标位置(为1)
	}
}

bool bfs()
{
	//cnt:这次bfs扩散了几张剪下来的邮票
	//tx:从head向上下左右走的下一个位置(数组下标)
	int cnt=0,tx,s,book[M]={0},nxt[4]={1,4,-1,-4};
	//队列存储的是 裁剪的数 在原一维数组中的位置(下标)
	queue<int> q;
	//(从剪下来的邮票中)获得起点
	s=gets();
	
	q.push(s);
	book[s]=1;
	cnt++;
	while(!q.empty()){
		auto head=q.front(); q.pop();
		
		for(int i=0;i<4;++i){
			tx=head+nxt[i];
			if(tx<0||tx>11) continue;
			//判断跨行 
			//注意:也可以改为if(head%4!=tx%4&&head/4!=tx/4) 
			//本质:只有+1,-1时跨行扩散不合法
			//    在+4,-4时跨行合法
			if(i==0||i==2) 
				if(head/4!=tx/4) continue;
			if(book[tx]==0&&isIna(tx)){//如果没搜过 且 在裁剪部分 
				q.push(tx);//入队 
				book[tx]=1;
				cnt++;
			}
		}
	}
	return cnt==5;
}

void getA(int s,int t)//12选5 获得排列 
{
	if(s==5){//获得一个排列 存储在a[0,4] 
		if(bfs()) ans++;//如果连通 ans++ 
		return ;
	}
	for(int i=s;i<=t;++i){
		swap(a[s],a[i]);
		getA(s+1,t);
		swap(a[s],a[i]);
	}
}

int main()
{
	getA(0,11);
	cout<<ans/120;//去重 
	return 0;
}
posted @ 2026-03-02 09:57  king_steph1209  阅读(14)  评论(0)    收藏  举报