ZOJ 3780 --Paint the Grid Again 逆向自然求解法

本文介绍了解决 ZJU ACM 在线评测系统中编号为 3780 的问题的方法。该问题涉及在一个矩阵中找到全 X 的行或全 O 的列,并按字典序最小的方式进行操作。通过逆向思考和反证法验证了算法的有效性,并提供了 C++ 实现代码。

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

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3780

个人解题思路:

1:逆向自然求解:找到全’X'行 或 全'O'列 删除(对应行/列元素全置0);

2:在任意时刻,不会存在 某行全为‘X' 的同时另外一列全为’O’;反证法:

      假设存在并且 全‘X’行的行号为i、 全‘O'列的列号为j ,则在矩阵中坐标为(i,j)的点由于还未被置0,所以其将即为‘X',又为'O',显然不可能。

   综上,结论得证。

  明白这一点,在循环中先处理 行 或 列  就都可以了,因为同一时刻二者只能有其一成立。

3:可能存在 多行同时为’X‘ 或多列同时为'O",根据题目要求要字典序最小,所以从后往前找时应优先处理 编号 大的行/列。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#include<list>
#include<stack>
#include<queue>
#include<string>
#include<algorithm>



using namespace std;
char matrix[500+5][500+5];
stack<string> stack_operation;
bool flag_row[500+5], flag_column[500+5];
int cnt_row=0,cnt_column=0;
int main(){

#ifndef ONLINE_JUDGE
    freopen("testCase.txt","r",stdin);
#endif
    int T;
    int N;
    scanf("%d",&T);
    while(T--){

        int counter=0;
        char str[5];
        memset(matrix,0,sizeof(matrix));
        memset(flag_row,0,sizeof(flag_row));
        memset(flag_column,0,sizeof(flag_column));
        scanf("%d",&N);
        for(int i=0;i<N;i++)
            scanf("%s",matrix[i]);
        counter = 2* N;
/* 这里处理时 找全'X'行  或  找全'O'列 不用区分先后,
 * 因为当前矩阵  有全'X'行 与 有全'O'列 是互斥的,二者某时刻只能有一成立
 */
        while(counter--){
            if(cnt_row==N || cnt_column==N)
                break;
            for(int i=N-1;i>=0;i--){   //行
                if(flag_row[i]==true)//已处理过
                    continue;
                for(int j=0;j<N;j++){//列
                    if(matrix[i][j]!='X'&&matrix[i][j]!=0)
                        break;
                    if(j==(N-1)){       //
                        for(int k=0;k<N;k++)
                            matrix[i][k] = 0;
                        flag_row[i] = true;
                        cnt_row++;
                        //itoa(i+1,str,10);
                        sprintf(str,"%d",i+1);
                        stack_operation.push("R"+string(str));
                    }
                }
            }
            if(cnt_row==N || cnt_column==N)
                break;

            for(int i=N-1;i>=0;i--){//列
                if(flag_column[i]==true)//已处理过
                    continue;
                for(int j=0;j<N;j++){//行
                    if(matrix[j][i]!='O'&&matrix[j][i]!=0)
                        break;
                    if(j==(N-1)){      
                        for(int k=0;k<N;k++) //行
                            matrix[k][i] = 0;
                        flag_column[i] = true;
                        cnt_column++;
                        //itoa(i+1,str,10);
                        sprintf(str,"%d",i+1);
                        stack_operation.push("C"+string(str));
                    }
                }
            }


        }
        if(stack_operation.size()==0)
            cout<<"No solution"<<endl;
        else{
            while(stack_operation.size()){

                cout<<stack_operation.top();

                stack_operation.pop();
                if(stack_operation.size()!=0)
                    cout<<' ';
                else 
                    cout<<endl;
            }
            //cout<<endl;
        }
    }


    return 0;
}


 

测试用例如下:

4
2
XX
OX
2
XO
OX
3
XOX
XOX
XOX
3
OOO
XOO
XXO

对应输出为:

R2 C1 R1
No solution
C1 C3 R1 R2 R3 C2
R1 C1 R2 C2 R3 C3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值