2024年3月22號題解

lwj1239發表於2024-03-23

Fliptile

解題思路

  1. 對於這個題目可以用遞推來寫
  2. 因為每次翻轉只會影響一個十字架的區域,所以如果我們知道第一行的情況,那麼是不是隻要把第一行的所有的1在對應的下一個行的相同位置進行翻轉就可以把第一行的所有的1變成0呢(重要性質)
  3. 那麼只要我們不斷遞推下去就可以得到最後一行的狀態,如果最後一行全是0,代表方案合法
  4. 那麼我們怎麼得到第一行的狀態呢?
  5. 很明顯第一行的狀態是固定的,只有2 ^ m列種情況
  6. 那麼我們只要列舉這2 ^ m列種情況就可以得到我們的答案
  7. 注意因為第一行的狀態可以由第一行的原始狀態,透過翻轉操作得到第一行所有狀態(注意列舉的是翻轉操作,不是第一行的狀態)
  8. 所有我們只要列舉翻轉的操作就可以了,同時題目也說叫我們列印翻轉的次數

程式碼實現

#include <iostream>
#include <cstring>
using namespace std;

const int N = 16;//矩陣最大規模
const int INF = 100000;//表示一個無窮大的數

int n;//矩陣的行數
int m;//矩陣的列數
int martix[N][N];//原始矩陣
int backup[N][N];//暫時存放原始矩陣,用來恢復現場
int ans[N][N];//最終的答案,即翻轉操作
int t[N][N];//每一次合法的答案
int d[5][2] = {
        {1, 0}, {-1, 0}, {0, 0}, {0, -1}, {0, 1}
};
int res = INF;//操作的次數初始化為一個極大值

void filp(int x, int y)//翻轉x,y位置的值
{
        for (int i = 0; i < 5; i++) {
                int nx = x + d[i][0];
                int ny = y + d[i][1];

                if (nx >= 0 && nx < n && ny >= 0 && ny < m) {
                        martix[nx][ny] ^= 1;
                }
        }
}

void solve()
{
    //讀入矩陣
        for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                        cin >> martix[i][j];
                        backup[i][j] = martix[i][j];
                }
        }

    //列舉所有的操作
        for (int i = 0; i < 1 << m; i++) {
                memset(t, 0, sizeof(t));//給t陣列全部賦值為0
                memcpy(martix, backup, sizeof(backup));//把backup陣列的內容複製到martix陣列
                int cnt = 0;//統計翻轉操作的次數
                //看第一行有那些位置需要翻轉
                for (int j = 0; j < m; j++) {
                        if (i >> j & 1) {
                                filp(0, j);//翻轉第一行的j位置
                                cnt++;//翻轉了一次計數器加一
                                t[0][j] = 1;//計入翻轉的位置
                        }
                }

                //只看到第n - 1行,因為最後一行沒有燈了,所以推到n - 1行就可以了
                for (int j = 0; j < n - 1; j++) {
                        for (int k = 0; k < m; k++) {
                                if (martix[j][k]) {//如果當前行的k位置是1,那麼我們要把它變成0,那麼就翻轉它的下一行的位置
                                        filp(j + 1, k);//翻轉下一行來改變當前位置
                                        t[j + 1][k] = 1;//翻轉的是下一行所以記錄j + 1位置
                                        cnt++;//翻轉了一次計數器加一
                                }
                        }
                }

                bool islaw = 1;//判斷方案是不是能夠讓矩陣全為0,1代表合法即最後矩陣全為0,0代表不合法,矩陣沒有全為0
                //遍歷最後一行
                for (int j = 0; j < m; j++) {
                        if (martix[n - 1][j]) {//如果有一個1
                                islaw = 0;//方案不合法
                                break;//跳出迴圈
                        }
                }

                if (islaw) {//方案合法
                        if (cnt < res) {//並且比之前的答案的操作次數還要更少
                                res = cnt;//更新最少的操作次數
                                memcpy(ans, t, sizeof(t));//把新的答案複製到ans陣列裡面去
                        }
                }
        }

        if (res != INF) {//如果res的值不是INF那麼代表有合法的方案
                //列印翻轉運算元組
                for (int i = 0; i < n; i++) {
                        for (int j = 0; j < m; j++) {
                                cout << ans[i][j] << ' ';
                        }
                        cout << '\n';
                }
        }
        else {//res == INF沒有合法的方案,列印不可能
                cout << "IMPOSSIBLE";
        }
}

int main()
{
        cin >> n >> m;//讀入矩陣的行和列

        solve();
        
        return 0;
}

Shuffle'm Up

解題思路

  1. 一道模擬題,根據樣例我們可以看出,它是每次分半組合,然後一直迴圈下去,但如果再次碰到第一次組合的結果,就代表無法得到想要的結果

程式碼解析

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#define u unsigned
#define ll long long
#define sc scanf
#define pr printf 
#define fr(i, j, n) for (int i = j; i < n; i++)
#define N 101

int t;

int main(int argc, char* argv[])
{
	sc("%d", &t);

	for (int i = 1; i <= t; i++) {
		int c;
		char s1[N] = { 0 };
		char s2[N] = { 0 };
		char s3[2 * N] = { 0 };
		char s4[2 * N] = { 0 };//³õʼ״̬ 
		char s5[2 * N] = { 0 };
		bool is = 0;

		sc("%d%s%s%s", &c, s1, s2, s3);

		for (int i = 0; i < c; i++) {
			s4[2 * i] = s2[i];
			s4[2 * i + 1] = s1[i];
		}

		for (int i = 0; i < 2 * c; i++) {
			s5[i] = s4[i];
		}

		int ans = 1;

		while (1) {
			for (int i = 0; i < c; i++) {
				s1[i] = s4[i];
				s2[i] = s4[i + c];
			}

			for (int i = 0; i < c; i++) {
				s4[2 * i] = s2[i];
				s4[2 * i + 1] = s1[i];
			}

			ans++;

			if (strcmp(s4, s3) == 0) {
				break;
			}

			if (strcmp(s4, s5) == 0) {
				is = 1;
				break;
			}
		}

		if (is) {
			pr("%d %d\n", i, -1);
		}
		else {
			pr("%d %d\n", i, ans);
		}
	}





	return 0;
}

相關文章