POJ2695(枚举)

这是一个关于POJ2695问题的解析,玩家需要通过开关冰箱上的16个把手来打开冰箱。每次操作会改变一行或一列所有把手的状态。目标是找出最小的操作数以使所有把手都处于打开状态。输入包含初始把手状态,输出是最小操作数及操作顺序。
摘要由CSDN通过智能技术生成

题目链接:http://poj.org/problem?id=2965


The Pilots Brothers' refrigerator
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 24836 Accepted: 9584 Special Judge

Description

The game “The Pilots Brothers: following the stripy elephant” has a quest where a player needs to open a refrigerator.

There are 16 handles on the refrigerator door. Every handle can be in one of two states: open or closed. The refrigerator is open only when all handles are open. The handles are represented as a matrix 4х4. You can change the state of a handle in any location [i, j] (1 ≤ i, j ≤ 4). However, this also changes states of all handles in row i and all handles in column j.

The task is to determine the minimum number of handle switching necessary to open the refrigerator.

Input

The input contains four lines. Each of the four lines contains four characters describing the initial state of appropriate handles. A symbol “+” means that the handle is in closed state, whereas the symbol “−” means “open”. At least one of the handles is initially closed.

Output

The first line of the input contains N – the minimum number of switching. The rest N lines describe switching sequence. Each of the lines contains a row number and a column number of the matrix separated by one or more spaces. If there are several solutions, you may give any one of them.

Sample Input

-+--
----
----
-+--

Sample Output

6
1 1
1 3
1 4
4 1
4 3
4 4

暴力无脑思路:枚举1~1^16种点开开关的方法,程序中用一个变量 key 代替, 但这个枚举并非按数字顺序(一开始是这么想的,但这样不好提前结束循环,可能会TLE)

    而是一个从小到大的点开关次数的dfs(即:尝试按0个开关,看是否满足,再尝试按1个开关,在尝试按2个开关......一直到16个开关全尝试完,这样可以
    保证第一次出现的答案即为次数最少的答案)

    这里的dfs可以用普通数组去存放需要按的开关,也可以直接用一个int变量(程序中的key)代替,对这个变量进行位操作,比如我们要按15号位的开关,

    那么我们就将key的第15位从0置为1, 利用   key =  key |   (1 << 15)   即可将第15位置为1   (这种思想在空间不够时可以利用,但在这里只是......装逼)

    还有反转操作可以利用异或, 这样比价快, 而且不用写一摞摞的判断.......

机智的做法:    有大神发现: 如果将某一按键所在的同一行和同一列的按键全按一次, 那么就等同于该按键自己反转的效果。 (我去,你怎么发现的,怎么我就发现不了...)

    这样就简单了,看有多少个开关要反转,统计多余的同行同列的反转开关,就得出结果了........(给跪了)

太久没打码真的菜啊,一开始卡dfs , 后来各种卡,前前后后花了一个多钟,而且思路不够好.......

#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <queue>
#include <cstdio>
#include <string.h>
#include <cstdlib>
#include <cmath>
#include <string>
typedef long long ll;
#define CLR(a) memset(a, 0, sizeof(a))
#define SD(a) scanf("%d", &a)
#define FOR(i, a, b)  for(i = a; i < b; i++)
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define MAXN 200000 + 10
using namespace std;

int mapp[4][4];
int key;

int dfs(int ceng, int start, int need)	
{

     if (ceng >= need)
     {
          int i, j, k;
          int tmp[4][4];
          memcpy(tmp, mapp, sizeof(mapp));
          for (i = 15; i >= 0; i--)
          {
               if ((key & (1 << i)) != 0)
               {
                    int n = 15 - i;
                    int posi = n / 4;
                    int posj = n % 4;
                    for (k = 0; k < 4; k++)
                    {
                         tmp[posi][k] = tmp[posi][k] ^ 1;		// 0 1 反转
                         tmp[k][posj] = tmp[k][posj] ^ 1;
                    }
                    tmp[posi][posj] = tmp[posi][posj] ^ 1;
               }
          }

          for (i = 0; i < 4; i++)
               for (j = 0; j < 4; j++)
                    if (tmp[i][j])
                         return 0;
          return 1;
     }
     else
     {
          if (start > 16)
               return 0;
          int i, j, tmp;
          for (i = start; i < 16; i++)
          {
               tmp = key;
               key = key | (1 << 16 - i - 1);
               if (dfs(ceng + 1, i + 1, need))
                    return 1;
               key = tmp;
          }
     }
     return 0;
}

int main()
{
     char tmp[5];
     int i, j, cnt;
     for (i = 0; i < 4; i++)
     {
          scanf("%s", tmp);
          for (j = 0; j < 4; j++)
               if (tmp[j] == '-')
                    mapp[i][j] = 0;
               else
                    mapp[i][j] = 1;

     }

     key = 0;

     for (i = 0; i <= 16; i++)			//从0次开始尝试
          if (dfs(0, 0, i))
               break;

     for (i = 16, cnt = 0; i >= 0; i--)
          if ((key & (1 << i)) != 0)
               cnt++;

     printf("%d\n", cnt);
     for (i = 15; i >= 0; i--)
          if ((key & (1 << i)) != 0)
               printf("%d %d\n", (3 - i / 4) + 1, (3 - i % 4) + 1);

     return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值