[2016/7/26][usaco 2.2]Party Lamps

本文分享了一道USACO竞赛题目“Lamps”的解题思路与代码实现过程。通过对每六位一个循环的特性分析,利用DFS算法解决状态遍历问题,并巧妙处理字典序输出要求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这两天因为身体原因没有写题,简直罪过罪过。今天要抓紧时间敲敲敲了qwq

http://train.usaco.org/usacoprob2?a=SzjbOuWGTGm&S=lamps

这是一道极其坑的题,调了昨天一下午+今天一早上。

思路倒没什么难的,每六位一个循环,按钮按两下等同于不按。所以最多有2^4种情况,dfs就行了。

关键是!输出要用字典序!!

简直神坑啊。。

又用的bitset,考虑到字典序,所以直接把bitset类型的二进制序列转换为整数,再针对这个排序,最后得出的就是字典序。

但是!!在bitset中,第一位是最右边一位数,如0001,第一位是1。

但是从输出看呢,第一位得是最左边一位数。所以在存储的时候,就要把原有结果逆序存,使它从左到右输出顺序符合题意。最后排序也按逆序的排,毕竟字典序。

中间还有些小细节需要处理,如把灯的标号转换成数组下标。好麻烦orz。

(不知道为什么调着调着就过了系列

代码如下:

/* 
ID:49743541 
LANG:C++ 
TASK:lamps 
*/  
#include <stdio.h>
#include <vector>
#include <bitset>
#include <iostream>
#include <algorithm>
using namespace std;
int N;
int C;
bitset<6> lamp[20];
bitset<6> real[20];
bitset<6> a;
bool flag[20];
int amount = 1;
void operate(int bot){
	if(bot==1)
		for(int i = 0;i<6;i++)
			a[i] = (!a[i]);
	else if(bot==2)
		for(int i = 0;i<6;i+=2)
			a[i] = (!a[i]);
	else if(bot==3)
		for(int i = 1;i<60;i+=2)
			a[i] = (!a[i]);
	else
		for(int i = 0;i<6;i+=3)
			a[i] = (!a[i]);
			
}
void dfs(int bot,int step){
	if(bot>=4) return;
	if(step>=C) return;
	operate(bot+1);
	for(int i = 0;i<6;i++)
		lamp[amount][i] = a[5-i];
	amount++;
	dfs(bot+1,step+1);
	operate(bot+1);
	dfs(bot+1,step);
}
int trans(int a){
	if(a%6==0)
		a = 0;
	else a = 6-a%6;
	return a; 
	
}
bool compare(bitset<6> A,bitset<6> B){
	if(A.to_ulong()<B.to_ulong())
		return true;
	return false;
}
int main(){
//	freopen("lamps.in", "r", stdin);  
//    freopen("lamps.out", "w", stdout);  
	a = ~a;
	lamp[0] = ~lamp[0];
	scanf("%d%d",&N,&C);
	if(C>4)
		C = 4;
	int count = 0;
	dfs(0,0);
	int k;
	for(int i = 0;i<amount;i++){
		if(!flag[i])
		for(int j = 0;j<i;j++){
			for(k = 0;k<6;k++){
				if(lamp[i][k]!=lamp[j][k]){
					break;
				}
			}
			if(k==6){
				flag[i] = true;
				break;
			}
		}
	}
	
	int on;
	scanf("%d",&on);
	while(on!=-1){
		on = trans(on);
		for(int i = 0;i<amount;i++){
			if(!flag[i]){
				if(lamp[i][on]!=1)
					flag[i] = true;
			}
		}
		scanf("%d",&on);
	}
	int off;
	scanf("%d",&off);
	while(off!=-1){
		off = trans(off);
		for(int i = 0;i<amount;i++){
			if(!flag[i]){
				if(lamp[i][off]!=0)
					flag[i] = true;
			}
		}
		scanf("%d",&off);
	}
	int len = 0;
	for(int i = 0;i<amount;i++){
		if(!flag[i]){	
			real[len] = lamp[i];
			len++;
		}
	}
	sort(real,real+len,compare);
	for(int i = 0;i<len;i++)
		cout<<real[i]<<endl;
	if(len==0) printf("IMPOSSIBLE\n"); 
	int s = N/6;
	int b = N%6;
	for(int i = 0;i<len;i++){
		for(int j = 0;j<s;j++)
			cout<<real[i];
		int p = 5;
		int x = b;
		while(x){
			cout<<real[i][p];
			p--;
			x--;
		}
		cout<<endl;
	}	
	return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值