zoj p3780 Paint the Grid Again

本文详细介绍了如何解决ZJU ACM在线评测题5267,该题涉及使用魔法刷将一个N*N的格子涂成黑色或白色,并给出了一种最小化涂色方案的方法。通过分析输入输出要求,作者提出了从后向前推导的策略,确保输出序列的最小性。

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

地址:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5267

 

题意:Leo 有一个N*N 的格子,他又有一把魔法刷,这个刷子能把一行刷成黑色,一列刷成白色,每一行或每一列都只能刷一次。刚开始时,格子既不是白色,也不是黑色。

输入:题目给了刷好后的格子,其中'X'代表黑,’O’代表白。

输出:输出涂法。每一步用”R#”或”C#”表示,”#”指代数字,”R#”表示涂第’#行,”C#”表示涂第”#”列。输出时输出最小方案。最小方案是指:C<R,”#”也应该尽可能小。

 

思路:如果是一个有解的输入,那必然有一行或一列是同色的,即不过怎么涂,你最后一笔必然会使一行或一列同色。可以从这点出发,倒推,发现一行或一列同色时,使其还原为这一步之前的状态。

注意:因为是倒推,所以每一步都应优先取行,再取列,然后行号或列号应尽可能大,才能使之输出的序列最小。

关于还原上一步,如果用’-’表示没涂的状态,要考虑每个方格上一部的状态是’X’还是’O’,亦或是’-’;

举例说明:

输入     XX

          OX

 

第一步:去第一行,

                   其中第一列有’O’,第二列没’O’,

                   所以可以化为:

                   O-

                   OX   //R1

第二步 :去第一列,

                   其中第一行没’X’,第二行有’X’

                   所以可以化为

                   - -

                   XX   //C1

第三步:去第二行,

                   其中第一列没’O’,第二列没’O’

                   所以可以化为

                   --

                   --  //R2

此时已经完成,逆序输出步骤即可

 

如果过程中不存在一行或一列是同色的,则可以判段此输入是非法的

 

/*
1500ms过的,一定还可以优化,
这次代码可能有点乱,请见谅
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <stack>
using namespace std;

typedef struct node{
    char dir;
    int order;
}node; //用于表示步骤,dir代表R或C,order代表行号或列号

const int maxn = 500+20;
bool row[maxn], column[maxn]; //记录此行是否涂过,记录此列是否涂过
char map[maxn][maxn];         //输入的格子图
int N;

inline void input() //输入
{
    cin>>N;
    int i,j;
    for(i=0;i<N;i++)
    {
        getchar();
        for(j=0;j<N;j++)
            scanf("%c",&map[i][j]);
           //cin>>map[i][j];
    }
    memset(row,false,sizeof(row));
    memset(column,false,sizeof(column)); //数组初始化
    return ;
}

int judge()   //判断是否已经回到最初的状态
{
    int i,j;
    for(i=0;i<N;i++)
        for(j=0;j<N;j++)
        if( map[i][j]!='-' )
        return 1;
    return 0;
}

inline void paint()
{
    stack <node> st; //存储步骤
    int i,j,k;
    int flag=0; //记录有没有找到一行或一列同色
    node t;
    //int turn=0;
    while( judge())
    {
        flag=0;
        for(i=N-1;i>=0;i--) //行'X'
        {
            if(row[i])
                continue;
            for( j=0;j<N;j++ )
                if(map[i][j]!='X') //是否有一行全部为‘X’
                break;
            if(j==N)
            {
                flag=1;
                break;
            }
        }

        if(flag)
        {
            row[i]=true;
            for(j=0;j<N;j++)
            {
                for(k=0;k<N;k++)
                    if( k!=i && map[k][j]=='O' )
                        break;
                if( k==N )
                    map[i][j]='-';
                else
                    map[i][j]='O';  //还原到上一步的状态
			}
            t.dir='R';
            t.order=i;
            st.push(t);
            continue;
        }

        flag=0;
        //cout<<turn<<endl;
        for(i=N-1;i>=0;i--) //列'O'
        {
            if(column[i])
                continue;
            for( j=0;j<N;j++ )
                if(map[j][i]!='O')  //是否有一列全部为‘O’
                break;
            if(j==N)
            {
                flag=1;
                break;
            }
        }

        if(flag)
        {
            column[i]=true;
            for(j=0;j<N;j++)
            {
                for(k=0;k<N;k++)
                    if( k!=i && map[j][k]=='X' )
                        break;
                if( k==N )
                    map[j][i]='-';
                else
                    map[j][i]='X';  //还原到上一步的状态
			}
            t.dir='C';
            t.order=i;
            st.push(t);
            continue;
        }
        else
            break; //没有找到一行或一列同色,退出
    }

    //输出
   if( judge() )
	   cout<<"No solution\n";
   else
   {
	  t=st.top();
	  st.pop();
	  printf("%c%d",t.dir,t.order+1);
	  while( !st.empty() )
	  {
		t=st.top();
		st.pop();
		printf(" %c%d",t.dir,t.order+1);
	  }
	  printf("\n");
   }
}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        input();
        paint();
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/Emerald/p/3954654.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值