D - Flip tile
2015-07-15 15:03
495 查看
题目大意翻瓷砖(姑且认为题目就是这个意思吧) 农民约翰知道越聪明越快乐的牛产的牛奶越多(神马鬼理论),于是他开始安排牛进行一个智力运动在一个M*N (1 ≤ M ≤ 15; 1 ≤ N ≤ 15) 的网格中,每个网格都有一个正方形的瓷砖组成,当然每块瓷砖都是由黑色和白色两种颜色组成的。 这个游戏是吧所有的瓷砖都变成白色??,奶牛在翻转瓷砖的时候会把四周的瓷砖一同翻转过来的,当然奶牛想用最少的步骤来翻转,如果有多种翻转方法,输出字典序最小的那个(矩形的字典序。。。。),如果不能完成翻转,输出IMPOSSIBLE。
通过观察可以看出来一共有 2 ^(M*N)种翻转方式,当然不能一种一种的实验,那样会超时到死的,不过通过观察可以看出来只要第一行的翻转方案确认了,那么下面的也可以知道了,因为如果有一个瓷砖需要翻转,本行翻转方法已经确认,那么一定在同列的下行翻转。这样只需要2^15就够了。写一下试试吧........
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
using namespace std;
#define maxn 30
const int oo = 0xffffff;
//本身和四周的位置,因为需要保存翻转的方法,所以不改变上层
int dir[4][2] = { {0,0},{0,1},{0,-1},{1,0} };
int G[maxn][maxn], ans[maxn][maxn];
int M, N;
//初始化第0层并且复制图到ans
void Start(int k)
{
int i, j;
for(i=N; i>0; i--)
{
ans[0][i] = k%2;
k /= 2;
}
for(i=1; i<=M; i++)
for(j=1; j<=N; j++)
ans[i][j] = G[i][j];
}
int OK()//判断翻转后的图是否合法
{
int i;
for(i=1; i<=N; i++)
if(ans[M][i])return 0;
return 1;
}
//翻转图,并且返回需要翻转的步数,若不能翻转成功则返回-1
int OverTurn()
{
int i, j, k, sum=0;
for(i=1; i<=M; i++)
for(j=1; j<=N; j++)
{
if(ans[i-1][j])
{
for(k=0; k<4; k++)
{
sum++;
int ni = i+dir[k][0];
int nj = j+dir[k][1];
ans[ni][nj] = !ans[ni][nj];
}
}
}
if(OK() == 0)
return -1;
return sum;
}
int main()
{
while(scanf("%d%d", &M, &N) != EOF)
{
int i, j, k=pow(2, N);
int sum = oo, p, q=-1;//sum 需要翻转的步数
for(i=1; i<=M; i++)
for(j=1; j<=N; j++)
scanf("%d", &G[i][j]);
for(i=0; i<=k; i++)
{
Start(i);
p = OverTurn();
if(p != -1 && sum > p)
sum = p, q = i;
}
if(q == -1)
printf("IMPOSSIBLE\n");
else
{
Start(q);
OverTurn();
for(i=0; i<M; i++)
for(j=1; j<=N; j++)
printf("%d%c", ans[i][j], j==N?'\n':' ');
}
}
return 0;}
通过观察可以看出来一共有 2 ^(M*N)种翻转方式,当然不能一种一种的实验,那样会超时到死的,不过通过观察可以看出来只要第一行的翻转方案确认了,那么下面的也可以知道了,因为如果有一个瓷砖需要翻转,本行翻转方法已经确认,那么一定在同列的下行翻转。这样只需要2^15就够了。写一下试试吧........
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
using namespace std;
#define maxn 30
const int oo = 0xffffff;
//本身和四周的位置,因为需要保存翻转的方法,所以不改变上层
int dir[4][2] = { {0,0},{0,1},{0,-1},{1,0} };
int G[maxn][maxn], ans[maxn][maxn];
int M, N;
//初始化第0层并且复制图到ans
void Start(int k)
{
int i, j;
for(i=N; i>0; i--)
{
ans[0][i] = k%2;
k /= 2;
}
for(i=1; i<=M; i++)
for(j=1; j<=N; j++)
ans[i][j] = G[i][j];
}
int OK()//判断翻转后的图是否合法
{
int i;
for(i=1; i<=N; i++)
if(ans[M][i])return 0;
return 1;
}
//翻转图,并且返回需要翻转的步数,若不能翻转成功则返回-1
int OverTurn()
{
int i, j, k, sum=0;
for(i=1; i<=M; i++)
for(j=1; j<=N; j++)
{
if(ans[i-1][j])
{
for(k=0; k<4; k++)
{
sum++;
int ni = i+dir[k][0];
int nj = j+dir[k][1];
ans[ni][nj] = !ans[ni][nj];
}
}
}
if(OK() == 0)
return -1;
return sum;
}
int main()
{
while(scanf("%d%d", &M, &N) != EOF)
{
int i, j, k=pow(2, N);
int sum = oo, p, q=-1;//sum 需要翻转的步数
for(i=1; i<=M; i++)
for(j=1; j<=N; j++)
scanf("%d", &G[i][j]);
for(i=0; i<=k; i++)
{
Start(i);
p = OverTurn();
if(p != -1 && sum > p)
sum = p, q = i;
}
if(q == -1)
printf("IMPOSSIBLE\n");
else
{
Start(q);
OverTurn();
for(i=0; i<M; i++)
for(j=1; j<=N; j++)
printf("%d%c", ans[i][j], j==N?'\n':' ');
}
}
return 0;}
相关文章推荐
- Java 类路径扫描
- 【leetcode】2. Add Two Numbers
- 观察者模式实例解析
- android常见类(Thread Handler Looper相关)
- 网站性能优化:动态缩略图技术实现思路
- DEMO阶段已完成,今天,要深入钻
- CommonJS 模块规范 1.1.1
- 如何使用 Docker 组件开发 Django 项目?
- 利用getViewTreeObserver().addOnGlobalLayoutListener()获得一个视图的高度
- laplacian算子的运用
- 成为一个优秀的嵌入式工程师所需技能
- Objective-C 编程艺术
- C++之可调用对象
- 所有的外汇平台和现货贵金属平台在中国都是对赌!
- 安卓uiautomator使用步骤
- 奔跑中的2015--碎碎随笔
- 在Python的Django框架中调用方法和处理无效变量
- keydown keypress keyup事件
- event.currentTarget与event.target的区别介绍
- POC(proof-of-concept)