洛谷P7724 远古档案馆(Ancient Archive)

题目背景

为了揭开月光能量背后的秘密,你来到了地下的远古档案馆。

远古一族的秘密与遗忘的知识悉数贮藏于这片被尘封的迷宫中,你能成功解谜,获知远古的知识吗?

题目描述

远古档案馆的中心是一个解谜:

  • 有一个 2\times 22×2 的网格,每个格子中要么有一个正整数,要么是空的;

  • 你可以进行若干次操作:每次操作中,你选择一个有正整数的格子和一个与之相邻的空格子,将正整数移到那个空格子中;

  • 给定网格的初始状态和最终状态,保证初始状态和最终状态中包含的正整数个数相同(设为 kk 个),且它们就是前 kk 个不同的正整数,问是否可以通过有限次操作从初始状态到达最终状态?

下图展示了一个包含三个正整数的网格经过两次操作的情况:

只有完成解谜,才能获得遗忘的知识,因此你希望尽快解决这个问题。

注意:网格中可能没有正整数,也可能没有空格。

输入格式

输入共包括四行,每行两个整数。

前两行描述了初始状态,后两行描述了最终状态,用 00 表示空格子。

输出格式

如果可以从初始状态到达最终状态,输出 Yes,否则输出 No

输入输出样例

输入 #1复制

2 1
3 0
0 2
3 1

输出 #1复制

Yes

输入 #2复制

2 1
4 3
3 4
2 1

输出 #2复制

No

说明/提示

【样例 1 解释】

如题目描述中图所示。


【样例 2 解释】

没有可移动的正整数,所以无法从初始状态到达与之不相等的最终状态。


【数据范围】

本题采用捆绑测试。

所有数据符合题目描述所述。

  • Subtask 1(40 points):不存在空格。
  • Subtask 2(60 points):无特殊限制。

上代码:

#include<iostream>
#include<cstdio>
using namespace std;
int a[5],b[5],num=0,k;
bool judge1(){
    if(a[1]==b[3]&&a[2]==b[4]){ //a的第一行与b的第二行相同 
        if(a[1]!=0&&a[2]!=0) return 1;
    }
    if(a[3]==b[1]&&a[4]==b[2]){ //a的第二行与b的第一行相同 
        if(a[3]!=0&&a[4]!=0) return 1;
    }
    if(a[1]==b[2]&&a[3]==b[4]){ //a的第一列与b的第二列相同
        if(a[1]!=0&&a[3]!=0) return 1;
    }
    if(a[2]==b[1]&&a[4]==b[3]){ //a的第二列与b的第一列相同 
        if(a[2]!=0&&a[4]!=0) return 1;
    }
    return 0;
}
bool judge2(){
    if(a[1]==b[1]&&a[2]==b[2]){ //a的第一行与b的第一行相同 
    	if(a[1]==0||a[2]==0) return 1;
    }
    if(a[3]==b[3]&&a[4]==b[4]){ //a的第二行与b的第二行相同 
    	if(a[3]==0||a[4]==0) return 1;
    }
    if(a[1]==b[1]&&a[3]==b[3]){ //a的第一列与b的第一列相同 
    	if(a[1]==0||a[3]==0) return 1;
    }
    if(a[2]==b[2]&&a[4]==b[4]){ //a的第二列与b的第二列相同 
    	if(a[2]==0||a[4]==0) return 1;
    }
    return 0;
}
bool judge3(){
    if(a[1]==b[1]&&a[4]==b[4]|| //a,b左上与右下相同 
       a[2]==b[2]&&a[3]==b[3]){ //a,b右上与左下相同 
         return 1;	
    }
    return 0;
}
bool same(){ //a,b四个格完全相同 
    if(a[1]==b[1]&&a[2]==b[2]&&a[3]==b[3]&&a[4]==b[4]) return 1;
	 return 0;
}
bool move(int x){
    swap(a[k],a[x]); //x格中数字移到空格位置 
    if((judge1()||judge2()||judge3())&&!same()) return 1;
    else swap(a[k],a[x]); //判断不成立,数字回到x格
    return 0;
}
int main(){
    scanf("%d %d %d %d",&a[1],&a[2],&a[3],&a[4]);
    scanf("%d %d %d %d",&b[1],&b[2],&b[3],&b[4]);
    for(int i=1;i<=4;i++){
    	if(a[i]==0){
    		num++; //记录空格个数 
    		k=i; //记录空格出现位置 
    	}
    }
    if(same()){ //四个格全部相同
        printf("Yes"); 
        return 0;
    }
    if(num==0){ //四个格全部不为空
        printf("No"); 
        return 0;
    }
    if(num>=2){ //空格个数两个及以上 
    	printf("Yes");
    	return 0;
    }
    //以下均为只存在一个空格的情况 
    if(judge1()||judge2()||judge3()){ //判断
    	printf("No");
    	return 0;
    }
    if(k==2||k==3){ //空格位置为2或3时 
	if(move(1)||move(4)){ //判断1,4格中数字移到空格位置时 
		printf("No");
    	return 0;
		}
	}
    if(k==1||k==4){ //空格位置为1或4时
	if(move(2)||move(3)){ //判断2,3格中数字移到空格位置时  
		printf("No");
    	return 0;
		} 
	}
    printf("Yes"); //全部不成立,结束 
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值