熄灯问题 && 飞行员兄弟 && 翻棋子

poj 1222 熄灯问题

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

–第二次按下同一个按钮时,将抵消第一次按下所产生的效果。
–每个按钮最多只需按一次。
–每个按钮按下的顺序对最后的结果没有影响。
–对第一行每个点亮的灯,只需按下第二行相应的灯,就可以熄
灭第一行所有的灯,那么如此重复下去,第1,2,3,4行的灯都可以熄灭。

位运算解法

//熄灯问题
#include <iostream>
#include <cstring>
using namespace std;
char old[10], lights[10], result[10];  //原数组,灯数组,结果数组

void SetBit(char &c, int i, int v)  //c代表第i行的字符,把第i行的第j位设置成v
{
    if(v) {
        c = c | (1 << i);
    }
    else 
        c = c & ~(1 << i);
}
//v = 1
//如果把第3位上的设置为1
//0010 0101 
//0010 0101 | 0000 1000 = 0010 1101   按位或运算

//v = 0
//如果把第2位上的位设置为0
//0010 0101
//~(1  << 2)= ~(0000 0100) = (1111 1011)
//0010 0101 & 1111 1011 = 0010 0001

int GetBit(char c, int i)  //取出c的第i位上的数字
{
    return (c >> i) & 1;
}
//0010   0001  右移3位   0000   0100 & 0000  0001 = 0

void FilpBit(char &c, int i)   //翻转c的第i位
{
    c = c ^ (1 << i);
}
//0010 0101
//翻转第3位上的数字
//0010 0101 ^ 0000 1000 = 0010 1101


void OutPutResult()
{
    for(int i = 0; i < 5; ++i)
        for(int j = 0; j < 6; ++j) {
            cout << GetBit(result[i], j);
            if(j < 5) cout << " ";
            else cout << endl;
        }
}

int main()
{
	int kase;
	cin>>kase;
	for(int i = 1;i <= kase ;i++)
	{
	    int v, switchs;
	    for(int i = 0; i < 5; ++i)
	        for(int j = 0; j < 6; ++j) {
	            cin >> v;
	            SetBit(old[i], j, v);
	        }
	    
	    for(int n = 0; n < 1 << 6; ++n) {  //6个开关,2的6次方种情况,  (1 << 6 == 2^6)
	        memcpy(lights, old, sizeof(old));  //还原lights数组
	        switchs = n;
	        for(int i = 0; i < 5; ++i) {
	            result[i] = switchs;  //  0 0 1 0 1 0
	            for(int j = 0; j < 6; ++j) {
	                if(GetBit(switchs, j)) {
	                    if(j > 0) FilpBit(lights[i], j - 1);  //翻转左边
	                    FilpBit(lights[i], j); //翻转本身
	                    if(j < 5) FilpBit(lights[i], j + 1); //翻转右边
	                }
	            }
	            if(i < 4) lights[i + 1] ^= switchs;
	            switchs = lights[i];
	        }
	        if(lights[4] == 0) {
	        	printf("PUZZLE #%d\n",i);
	            OutPutResult();
	            break;
	        }
	    }
	}
    return 0;
}

局部替代整体
借鉴某位大佬的 博客

#include<stdio.h>
int puzzle[6][8],press[6][8];

bool guess(){
	int c,r;
	for(r=1;r<5;++r){
		for(c=1;c<7;++c){
			press[r+1][c]=(puzzle[r][c]+press[r][c-1]+press[r][c]+press[r][c+1]+press[r-1][c])%2;
		}//根据press第一行和puzzle数组计算press的其他值
	}
		for(c=1;c<7;++c){
			if((press[5][c-1]+press[5][c]+press[5][c+1]+press[4][c])%2!=puzzle[5][c])
			return false;
		}// 
		return true;
}

void zhenghe(){//将数据进行整合
	int c;
	bool success;
	for(c=1;c<7;c++){
		press[1][c]=0;
	}
	while(guess()==false){//当没有正确答案时,继续下去。找到正确的答案为止
		press[1][1]++;
		c=1;
		while(press[1][c]>1){
			press[1][c]=0;
			c++;
			press[1][c]++;//模拟二进制,六位二进制
		}
	}
	return;
}
int main(){
	int n,i,r,c,a=1;
	scanf("%d",&n);
	for(r=0;r<6;++r){
		press[r][0]=0;
		press[r][7]=0;
	}
	for(c=1;c<7;++c){
		press[0][c]=0;
	}
	for(i=0;i<n;++i){
		for(r=1;r<6;++r){
			for(c=1;c<7;++c){
				scanf("%d",&puzzle[r][c]);//输入
			}
		}
	zhenghe();
	printf("PUZZLE #%d\n",a);a++;
	for(r=1;r<6;++r){
			for(c=1;c<7;++c){
				printf("%d ",press[r][c]);//输出
			}
			printf("\n");
		}
	}
	return 0;	
}

飞行员兄弟 4*4

在这里插入图片描述
在这里插入图片描述

#include <cstdio>
using namespace std;
char s[4];
int mp[4][4];
int main()
{
    int arr=0;
    for(int i=0;i<4; i++)
    {
        scanf("%s",s);
        for(int j=0; j<4; j++)
        {
            if(s[j] == '+')
            {
                for(int k=0; k<4; k++)
                {
                    mp[i][k] ++;
                    mp[k][j] ++;
                }
            mp[i][j] --;
        	}
        }
    }
    for(int i=0; i<4; i++)
    {
        for(int j=0; j<4; j++)
        {
            if(mp[i][j] % 2 == 1)
                arr ++;
        }
    }
    printf("%d\n",arr);
    for(int i=0; i<4; i++)
    {
        for(int j=0; j<4; j++)
        {
            if(mp[i][j] % 2 == 1)
                printf("%d %d\n",i + 1, j + 1);
        }
    }
    return 0;
}

翻棋子游戏 poj 1753

在这里插入图片描述
在这里插入图片描述

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
 
struct node
{
    int x;         //用十进制的整数的后16位表示该节点的状态
    int steps;     //记录到达该节点的步数
    int i;         //是翻动哪个棋子到达当前的状态,避免返回以前的状态
};
 
bool vis[100000]={false};
char str[10];
node queue[100000];
 
void flip(int i,node a,node &b)    //i=当前要翻动的棋子编号(0-15),a为queue[p]的形参,b为queue[q]的引用
{
    int r=i/4,c=i%4;       //r、c为当前的要翻动的第i个棋子的行和列坐标
    b.x=a.x;               //为了不改变前一次记录的状态,先拷贝给b。再来翻棋子,记录新状态。
    b.x=b.x^(0x1<<i);         //用^0x1取反(0x1表示16进制的1)
    if(r>0)
        b.x=b.x^(0x1<<(i-4));     //翻i对应位置上面的棋子
    if(r<3)
        b.x=b.x^(0x1<<(i+4));     //翻i对应位置下面的棋子
    if(c>0)
        b.x=b.x^(0x1<<(i-1));     //翻i对应位置左边的棋子
    if(c<3)
        b.x=b.x^(0x1<<(i+1));     //翻i对应位置右边的棋子
    b.i=i;
    b.steps=a.steps+1;
}
void init()
{
    queue[0].x=0;             //初始化为16进制的0 (10进制和16进制的0是一样的)
    queue[0].steps=0;
    queue[0].i=-1;
    for(int i=0;i<4;i++)
    {
        scanf("%s",str);
        for(int j=0;j<4;j++)
        {
            if(str[j]=='b')         //黑棋对应的位置置1 (用|0x1置1)
                queue[0].x=(queue[0].x|(0x1<<i*4+j));
        }
    }
}
void bfs()
{
    int p=0,q=0;
    while(!(queue[q].x==0||queue[q].x==0xffff))     //如果不满足全0或者全1的状态
    {
        for(int i=0;i<16;i++)
        {
            if(queue[p].i==i)        
                continue;
            q++;                             //尾指针后移,为新状态开辟新的记录空间
            flip(i,queue[p],queue[q]);
            if(vis[queue[q].x])
                q--;
            vis[queue[q].x]=true;
            if(queue[q].x==0||queue[q].x==0xffff)
                break;
        }
        if(p==q)
        {
            printf("Impossible\n");
            break;
        }
        p++;                //头指针后移1位,将当前状态作为搜索的初始状态
    }
    if(queue[q].x==0||queue[q].x==0xffff)
        printf("%d",queue[q].steps);
}
int main()
{
    init();
    bfs();
    return 0;
}
发布了60 篇原创文章 · 获赞 22 · 访问量 6980

猜你喜欢

转载自blog.csdn.net/weixin_43786143/article/details/89117302