您的位置:首页 > 其它

POJ 2965

2016-12-04 12:20 134 查看
The Pilots Brothers’ refrigerator Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 24912 Accepted: 9611 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

Source

Northeastern Europe 2004, Western Subregion

看到是枚举的专题,看了下紫书上面关于子集枚举的专题。由于子集枚举没有按照元素多少排序,所以先按照元素多少排序,然后一个一个试。果然TLE。

tle代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#define inf 1000000000
using namespace std;
typedef long long ll;

char s[10][10];
int a[10][10];
int t[10][10];

struct note
{
int v;
int b[20];
}c[70000];

int tmp[20];
int cnt;
void dfs(int cur)
{
if(cur==16)
{
for(int i=0;i<16;i++)
{
c[cnt].b[i]=tmp[i];
}
cnt++;
}
else
{
tmp[cur]=0;
dfs(cur+1);
tmp[cur]=1;
dfs(cur+1);
}
}

int cmp(note x,note y)
{
return x.v<y.v;
}

void fan(int index)
{
int x=index/4;
int y=index%4;
for(int i=0;i<4;i++)
{
a[x][i]=!a[x][i];
a[i][y]=!a[i][y];
}
a[x][y]=!a[x][y];
}

int solve(int x)
{
for(int i=0;i<16;i++)
{
if(c[x].b[i]==1)
{
fan(i);
}
}
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
if(a[i][j]==1)
{
return 0;
}
}
}
return 1;
}

int main()
{
for(int i=0;i<4;i++)
{
scanf("%s",s[i]);
}
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
if(s[i][j]=='-')
{
a[i][j]=0;
}
else
{
a[i][j]=1;
}
}
}
dfs(0);
for(int i=0;i<cnt;i++)
{
int ttt=0;
for(int j=0;j<16;j++)
{
if(c[i].b[j]==1)
{
ttt++;
}
}
c[i].v=ttt;
}
sort(c,c+cnt,cmp);
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
t[i][j]=a[i][j];
}
}
for(int i=1;i<cnt;i++)
{
if(solve(i))
{
printf("%d\n",c[i].v);
for(int j=0;j<16;j++)
{
if(c[i].b[j])
{
int x=j/4;
int y=j%4;
printf("%d %d\n",x+1,y+1);
}
}
return 0;
}
else
{
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
a[i][j]=t[i][j];
}
}
}
}
return 0;
}


后来看网上代码思路

http://www.cnblogs.com/Java-tp/p/3873557.html

假如开关坐标为第二行第三列的(2,3),那么按照上述策略(把开关本身以及其同一行同一列的开关都进行一次操作),结果分析如下:

对于黄色部分的开关,只有与此黄色开关同一行和同一列的两个红色开关操作时,此黄色开关的状态才会发生改变,因此所有黄色部分状态改变次数为2,相当于0次

对于红色部分的开关,只有与此红色开关同一列或同一列的开关操作时,此红色开关状态才会发生改变,一行或者一列有4个开关,因此红色部分开关状态改变次数为4,相当于0次

对于最原始的那个黑色开关,所有红色开关操作时,它的状态改变一次,然后黑色开关自己操作一次,因此黑色开关状态改变7次,相当于改变1次。

总结上述分析可以得出结论,把开关本身以及其同一行同一列的开关都进行一次操作,最终结果是只有开关本身状态发生变化,其他所有开关状态都不变。

策略找到之后,那我们就想,如果对于所有关闭着的开关都进行一次上述策略,那么肯定是能把冰箱打开的,下面我们要做的就是把一些无用的,重复的操作去掉即可。

用一个4*4的数组记录每个开关操作的次数,初始化为0,开关操作一次,记录就+1

对于样例中的每一个+开关,进行一次策略,记录数组所记录的每一个开关操作的次数变化如上所示。那么在最终得到的数组中可以看出,有些开关操作了偶数次,有些操作了奇数次。操作了偶数次的开关就是上面所说的无用的,重复的操作,直接去掉,留下奇数次的就最终的答案。

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#define inf 1000000000
using namespace std;
typedef long long ll;

int a[10][10];
char s[10][10];
int c[10][10];

void solve(int x,int y)
{
for(int i=0;i<4;i++)
{
c[x][i]++;
c[i][y]++;
}
c[x][y]--;
}

int main()
{
for(int i=0; i<4; i++)
{
scanf("%s",s[i]);
}
for(int i=0; i<4; i++)
{
for(int j=0; j<4; j++)
{
if(s[i][j]=='-')
{
a[i][j]=0;
}
else
{
a[i][j]=1;
}
}
}
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
if(a[i][j]==1)
{
solve(i,j);
}
}
}
int cnt=0;
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
if(c[i][j]%2==1)
{
cnt++;
}
}
}
printf("%d\n",cnt);
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
if(c[i][j]%2==1)
{
printf("%d %d\n",i+1,j+1);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: