CH0503 奇数码问题

题意

给出两个n∗nn*nnn的矩阵,一个起始矩阵,一个目标矩阵,包含[1,n∗n−1][1,n*n-1][1,nn1]的整数和一个空格,可以上下左右移动该空格。问是否可以通过若干操作,使得起始矩阵变为目标矩阵。

思路

将矩阵的数字从上到下从左到右依次排列为长度为n∗n−1n*n-1nn1的序列(去掉空格),若初始矩阵和目标矩阵的逆序对数的奇偶性相同,则可以,否则不行。

代码

#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <iostream>
using namespace std;

#define fo(i, x, y) for (int i = x; i <= y; ++i)
#define fd(i, x, y) for (int i = x; i >= y; --i)

typedef long long ll;

const int maxnn = 250000 + 5;

int n;
int a[maxnn], b[maxnn];

int getint()
{
	char ch;
	int res = 0, p;
	while (!isdigit(ch = getchar()) && (ch ^ '-'));
	p = ch == '-'? ch = getchar(), -1 : 1;
	while (isdigit(ch))
		res = (res << 3) + (res << 1) + (ch ^ 48), ch = getchar();
	return res * p;
}

ll merge(int l, int r)
{
	if (l >= r) return 0;
	int mid = (l + r) >> 1;
	ll ans = merge(l, mid) + merge(mid + 1, r);
	int pl = l, pr = mid + 1;
	fo(i, l, r)
		if (pr > r || pl <= mid && a[pl] <= a[pr]) b[i] = a[pl++];
			else b[i] = a[pr++], ans += mid - pl + 1;
	fo(i, l, r) a[i] = b[i];
	return ans;
}

int main()
{
	while (~scanf("%d", &n) && n)
	{
		int p;
		fo(i, 0, n - 1)
			fo(j, 0, n - 1)
			{
				a[i * n + j] = getint();
				if (!a[i * n + j]) p = i * n + j;
			}
		fo(i, p, n * n - 2) a[i] = a[i + 1];
		ll sa = merge(0, n * n - 2);
		fo(i, 0, n - 1)
			fo(j, 0, n - 1)
			{
				a[i * n + j] = getint();
				if (!a[i * n + j]) p = i * n + j;
			}
		fo(i, p, n * n - 2) a[i] = a[i + 1];
		ll sb = merge(0, n * n - 2);
		if ((sa & 1) && (sb & 1) || !(sa & 1) && !(sb & 1)) printf("TAK\n");
			else printf("NIE\n");
	}
	return 0;
}
#include <reg52.h> #include <intrins.h> #define uchar unsigned char #define uint unsigned int // 矩阵按键定义 sbit ROW1 = P1^7; sbit ROW2 = P1^6; sbit ROW3 = P1^5; sbit ROW4 = P1^4; sbit COL1 = P1^3; sbit COL2 = P1^2; sbit COL3 = P1^1; sbit COL4 = P1^0; // 数码管位选定义,DIG1显示数据,DIG2显示校验位 sbit DIG1 = P2^0; sbit DIG2 = P2^4; // 数码管段码表0-F及熄灭 uchar code seg_table[] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, // 0-4 0x6D, 0x7D, 0x07, 0x7F, 0x6F, // 5-9 0x77, 0x7C, 0x39, 0x5E, 0x79, // A-E 0x71, 0x00 // F, 熄灭 }; // 按键值对应字符0-F uchar code key_char[] = { '0','1','2','3', '4','5','6','7', '8','9','A','B', 'C','D','E','F' }; // 帧格式定义 #define FRAME_HEAD 0xAA // 帧头 #define FRAME_TAIL 0x55 // 帧尾 // 接收缓冲区及相关变量 uchar receive_buf[4]; // 0:帧头, 1:数据, 2:校验位, 3:帧尾 uchar receive_count = 0; // 接收计数0-3 bit frame_valid = 0; // 有效帧标志 // 显示相关变量 uchar local_data = 0; // 本地发送数据 uchar local_parity = 0; // 本地校验位 uchar remote_data = 0; // 远程接收数据 uchar remote_parity = 0; // 远程校验位 bit is_local = 0; // 显示本地/远程数据标志 // 延时函数 void delay_ms(uint ms) { uint i, j; for(i = 0; i < ms; i++) for(j = 0; j < 120; j++); } // 串口初始化,9600波特率,模式1,允许中断 void uart_init() { TMOD = 0x20; // 定时器1工作模式2 TH1 = 0xFD; // 9600波特率初值 TL1 = 0xFD; TR1 = 1; // 启动定时器1 SCON = 0x50; // 串口模式1,允许接收 PCON = 0x00; // SMOD=0 ES = 1; // 允许串口中断 EA = 1; // 允许总中断 } // 串口发送1字节 void uart_send_byte(uchar dat) { SBUF = dat; while(!TI); // 等待发送完成 TI = 0; // 清除发送标志 } // 计算校验位 uchar calc_odd_parity(uchar dat) { uchar count = 0; uchar i; for(i = 0; i < 8; i++) { if(dat & (1 << i)) { count++; } } return (count % 2 == 0) ? 1 : 0; } // 按键扫描,返回0-15对应0-F,0xFF表示无按键 uchar key_scan() { uchar key_value = 0xFF; uchar row, col; // 先扫描列,输出低电平 P1 = 0x0F; if(P1 != 0x0F) { delay_ms(10); // 消抖 if(P1 != 0x0F) { // 确定列 if(COL1 == 0) col = 0; else if(COL2 == 0) col = 1; else if(COL3 == 0) col = 2; else if(COL4 == 0) col = 3; else return 0xFF; // 再扫描行,输出低电平 P1 = 0xF0; if(ROW1 == 0) row = 0; else if(ROW2 == 0) row = 1; else if(ROW3 == 0) row = 2; else if(ROW4 == 0) row = 3; else return 0xFF; key_value = row * 4 + col; // 等待按键释放 while(P1 != 0xF0); } } return key_value; } // 字符转数码管段码 uchar char_to_seg(uchar ch) { if(ch >= '0' && ch <= '9') { return seg_table[ch - '0']; } else if(ch >= 'A' && ch <= 'F') { return seg_table[ch - 'A' + 10]; } else if(ch >= 'a' && ch <= 'f') { return seg_table[ch - 'a' + 10]; } else { return 0x00; // 无效字符不显示 } } // 静态显示(去掉切换逻辑) void display_digit() { // 只显示本地数据(如果需要显示远程数据,把if条件改为false即可) if(1) { // 固定显示本地数据 // 显示本地发送的数据和校验位 DIG1 = 1; DIG2 = 0; P0 = char_to_seg(key_char[local_data]); delay_ms(2); DIG1 = 0; DIG2 = 1; P0 = seg_table[local_parity]; delay_ms(2); } else { // 如需固定显示远程数据,把上面的1改为0即可 // 显示远程接收的数据和校验位 DIG1 = 1; DIG2 = 0; P0 = char_to_seg(remote_data); delay_ms(2); DIG1 = 0; DIG2 = 1; P0 = seg_table[remote_parity - '0']; delay_ms(2); } } // 串口中断服务函数 void uart_isr() interrupt 4 { uchar rec; if(RI) { RI = 0; // 清除接收标志 rec = SBUF; if(receive_count == 0) { // 等待帧头 if(rec == FRAME_HEAD) { receive_buf[0] = rec; receive_count = 1; } } else { // 依次接收数据、校验位、帧尾 receive_buf[receive_count] = rec; receive_count++; // 接收完成4字节 if(receive_count >= 4) { if(receive_buf[3] == FRAME_TAIL) { frame_valid = 1; // 标记有效帧 remote_data = receive_buf[1]; remote_parity = receive_buf[2]; } receive_count = 0; // 重置接收计数 } } } } void main() { uchar key_val; uart_init(); local_data = 0; local_parity = 0; while(1) { // 按键扫描与发送 key_val = key_scan(); if(key_val != 0xFF) { local_data = key_val; // 计算校验位并保存 local_parity = calc_odd_parity(key_char[key_val]); // 发送数据帧 uart_send_byte(FRAME_HEAD); uart_send_byte(key_char[key_val]); uart_send_byte(local_parity + '0'); uart_send_byte(FRAME_TAIL); delay_ms(200); // 防抖动 } // 处理接收到的有效帧 if(frame_valid) { frame_valid = 0; // 清除标志 // 远程数据已在中断中保存 } // 刷新显示 display_digit(); } }修改我给出的代码,添加一个验证校验结果是否正确的功能
11-13
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值