POJ 3279 <牛踩格子>

虽然看了题解,一发AC还是美滋滋的。

枚举一部分情况,根据这些枚举的结果进行推导。

题意是给一个网格,网格有0有1,其中0代表这这个格子的颜色为白,1代表着这个格子的颜色为黑。(每次反转颜色由黑色转为白色或从白色转为黑色)

为了提高牛的智商..(好厉害的农场主),所以农场主让牛玩游戏,牛每次选择一个格子,这个格子会反转(同时其上下左右的格子都反转),对于边界,如最左上角,只反转3个,问牛最少需要选择几个格子可以做到将全部网格变白色,如果有相同个数,输出字典序最小的那种踩格子方案。

刚开始第一次看这个题并不能看懂,过了一遍挑战程序设计竞赛的中级篇重新看以后才明白的。

如果枚举全部可能是2^(r*c)种可能,虽然r,c<=15,但是还是太慢。

可以有这么一个方法,假设第一排踩格子的方法已经确定,从第二排开始我们就能确定踩还是不踩了。

如,如果第r-1行第c列为黑格子,那么显然只有第r行第c列能改变这个格子的颜色(从上到下推),为了让全部格子变白色,那么第r行第c列的格子必定得踩,第r-1行c+1列的格子为黑色,那么通过选择由第r行第c+1列的格子让其变成白色。这样推到第r行第c列的时候,从开头到第r行第c-1列就全为白色了。

那么当推完到最后一个的时候,只保证了前面c-1行全部为白色,那么只需要判断第r行是否全部为白色,如果全部为白色,那么这是一个可行方案。

所以通过枚举第一行的2^c种可能让第一行的情况确定,就可以推着求解了,其中要求字典序最小,二进制枚举的时候,1从右边开始增加就好了。

AC代码

#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
#include <stdlib.h>
#include <set>
#include <algorithm>
#include <map>
using namespace std;
int qq[20][20];
int fan[20][20];
int q1[20][20];
int r,c;
int fun1(int x){
	if(x==1)
	return 0;
	else return 1;
}
int fun2(int r,int c){
    int t1=fan[r-1][c]+fan[r-2][c]+fan[r-1][c-1]+fan[r-1][c+1]+qq[r-1][c];
    return t1;
}
int fun(int t1){
	int i,j;
	for(i=2;i<=r;i++)
		for(j=1;j<=c;j++)
			if(fun2(i,j)%2==1){
             fan[i][j]=1;       //路麓脳陋脪禄麓脦i,j
			t1++;
			}else{
            fan[i][j]=0;
			}
	int t2=0;
	for(j=1;j<=c;j++)
	if(fun2(r+1,j)%2==1)t2=1; //涓洪粦鑹?
	if(t2==1)return 0;
	else return t1;
}
int main(){
	int i,j,k,f1,f2,f3,f4,t1,t2,t3,t4;
	//freopen("in.txt","r",stdin);
	cin >> r>> c;
	memset(qq,0,sizeof(qq));
	for(i=1;i<=r;i++){
		for(j=1;j<=c;j++){
			cin >> qq[i][j];
		}
	}
	t2=1e9+7;
	memset(fan,0,sizeof(fan));
	memset(q1,0,sizeof(q1));
	for(i=0;i<1<<c;i++){
        t1=0;
        for(j=0;j<c;j++){
            if(i>>j&1){ //j涓嶄负0
            fan[1][c-j]=1; //寰楃煡绗竴琛岀炕涓庝笉缈?
            t1++;
            }else{
            fan[1][c-j]=0;
            }
        }
    //cout << i << "aaa " <<t1 <<endl;
        t3=fun(t1);
    //cout << i << " bbb  " << t3 << endl;
        if(t3&&t3<t2){
            t2=t3;
           // cout << t2<< endl;
            for(k=1;k<=r;k++)
                for(j=1;j<=c;j++)
                    q1[k][j]=fan[k][j];
         //   cout << "涓€娆? << endl;
        }
	}
	if(t2==1e9+7)
    cout <<"IMPOSSIBLE"<<endl;
    else{
        for(i=1;i<=r;i++){
                for(j=1;j<=c;j++)
            cout << q1[i][j] <<" ";
        cout << endl;
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值