POJ 3279 Fliptile (二进制+搜索)
来源:互联网 发布:江苏大学网络教学平台 编辑:程序博客网 时间:2024/05/01 00:06
【题目链接】click here~~
【题目大意】:
农夫约翰知道聪明的牛产奶多。于是为了提高牛的智商他准备了如下游戏。有一个M×N 的格子,每个格子可以翻转正反面,它们一面是黑色,另一面是白色。黑色的格子翻转后就是白色,白色的格子翻转过来则是黑色。游戏要做的就是把所有的格子都翻转成白色。不过因为牛蹄很大,所以每次翻转一个格子时,与它上下左右相邻接的格子也会被翻转。因为翻格子太麻烦了,所以牛都想通过尽可能少的次数把所有格子都翻成白色。现在给定了每个格子的颜色,请求出用最小步数完成时每个格子翻转的次数。最小步数的解有多个时,输出字典序最小的一组。解不存在的话,则输出IMPOSSIBLE。
【解题思路】:
首先,同一个格子翻转两次的话就会恢复原状,所以多次翻转是多余的。此外,翻转的格子的集合相同的话,其次序是无关紧要的。因此,总共有2NM种翻转的方法。不过这个解空间太大了,我们需要想出更有效的办法。让我们再回顾一下前面的问题。在那道题中,让最左端的牛反转的方法只有1种,于是用直接判断的方法确定就可以了。同样的方法在这里还行得通吗?不妨先看看最左上角的格子。在这里,除了翻转(1,1)之外,翻转(1,2)和(2,1)也可以把这个格子翻转,所以像之前那样直接确定的办法行不通。于是不妨先指定好最上面一行的翻转方法。此时能够翻转(1,1)的只剩下(2,1)了,所以可以直接判断(2,1)是否需要翻转。类似地(2,1)~(2,N)都能这样判断,如此反复下去就可以确定所有格子的翻转方法。最后(M,1)~(M,N)如果并非全为白色,就意味着不存在可行的操作方法。像这样,先确定第一行的翻转方式,然后可以很容易判断这样是否存在解以及解的最小步数是多
少,这样将第一行的所有翻转方式都尝试一次就能求出整个问题的最小步数。这个算法中最上面一行的翻转方式共有2N种,复杂度为O(MN2N)。
代码:
// C#ifndef _GLIBCXX_NO_ASSERT#include <cassert>#endif#include <cctype>#include <cerrno>#include <cfloat>#include <ciso646>#include <climits>#include <clocale>#include <cmath>#include <csetjmp>#include <csignal>#include <cstdarg>#include <cstddef>#include <cstdio>#include <cstdlib>#include <cstring>#include <ctime>#if __cplusplus >= 201103L#include <ccomplex>#include <cfenv>#include <cinttypes>#include <cstdalign>#include <cstdbool>#include <cstdint>#include <ctgmath>#include <cwchar>#include <cwctype>#endif// C++#include <algorithm>#include <bitset>#include <complex>#include <deque>#include <exception>#include <fstream>#include <functional>#include <iomanip>#include <ios>#include <iosfwd>#include <iostream>#include <istream>#include <iterator>#include <limits>#include <list>#include <locale>#include <map>#include <memory>#include <new>#include <numeric>#include <ostream>#include <queue>#include <set>#include <sstream>#include <stack>#include <stdexcept>#include <streambuf>#include <string>#include <typeinfo>#include <utility>#include <valarray>#include <vector>#if __cplusplus >= 201103L#include <array>#include <atomic>#include <chrono>#include <condition_variable>#include <forward_list>#include <future>#include <initializer_list>#include <mutex>#include <random>#include <ratio>#include <regex>#include <scoped_allocator>#include <system_error>#include <thread>#include <tuple>#include <typeindex>#include <type_traits>#include <unordered_map>#include <unordered_set>#endifusing namespace std;#define rep(i,j,k) for(int i=(int)j;i<(int)k;++i)#define per(i,j,k) for(int i=(int)j;i>(int)k;--i)#define lowbit(a) a&-a#define Max(a,b) a>b?a:b#define Min(a,b) a>b?b:a#define mem(a,b) memset(a,b,sizeof(a))typedef long long LL;typedef unsigned long long LLU;typedef double db;const int N=16;const int inf=0x3f3f3f3f;int n,m,t,ans,res,cnt,tmp;char str[N];bool vis[N];int mat[N][N];///状态之前int flip[N][N];///状态中间int Res[N][N];///状态之后int dir4[4][2]= {{1,0},{0,1},{-1,0},{0,-1}};int dir8[8][2]= {{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1}};int movv[5][2]= {{1,0},{0,1},{0,0},{-1,0},{0,-1}};using namespace std;inline LL read(){ int c=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} return c*f;}bool ok(int dx,int dy){ if(dx>=0&&dx<n&&dy>=0&&dy<m) return true; return false;}void getMat()///输入{ for(int i=0; i<n; ++i) for(int j=0; j<m; ++j) scanf("%d",&mat[i][j]);}int getChange(int x,int y)///判断x,y的颜色{ int c=mat[x][y]; for(int i=0; i<5; ++i) { int dx=x+movv[i][0]; int dy=y+movv[i][1]; if(ok(dx,dy))c+=flip[dx][dy]; } return c&1;///奇数为1,偶数为0}int calc(){ ///求出第二行开始的翻转方法 for(int i=1; i<n; ++i){ for(int j=0; j<m; ++j){ if(getChange(i-1,j)!=0)///是白色翻转 flip[i][j]=1; } } ///判断最后一行是否全白 for(int j=0; j<m; ++j){ if(getChange(n-1,j)!=0) return -1; } int sum=0;///统计翻转次数 for(int i=0; i<n; ++i){ for(int j=0; j<m; ++j){ sum+=flip[i][j]; } } return sum;}void solve(){ int res=inf; for(int i=0; i< (1<<m); ++i){///枚举第一行的情况 mem(flip,0); for(int j=0; j<m; j++){ flip[0][m-j-1] = i >> j & 1; } int now=calc(); if(now>=0&&now<res){ res=now; memcpy(Res,flip,sizeof(flip)); } } if(res!=inf){ for(int i=0; i<n; ++i){ for(int j=0; j<m; ++j){ printf("%d%c",Res[i][j],j==m-1?'\n':' '); } } } else puts("IMPOSSIBLE");}int main(){ while(cin>>n>>m){ getMat(); solve(); } return 0;}</span>
- POJ 3279 Fliptile (二进制+搜索)
- 【POJ】3279 Fliptile(十字变换搜索+二进制枚举)
- POJ.3279 Fliptile (搜索+二进制枚举+开关问题)
- POJ 3279 Fliptile 二进制
- POJ 3279 Fliptile 反转 (二进制枚举)
- poj 3279 Fliptile(搜索)
- POJ 3279 Fliptile (搜索)
- poj 3279 Fliptile(二进制暴力)
- poj 3279 Fliptile 二进制枚举
- 【POJ 3279】Fliptile(状压DP+搜索)
- POJ-3279(Fliptile)--简单搜索
- 不懂 POJ 3279-Fliptile【搜索】
- POJ 3279 Fliptile(普通搜索)
- POJ 3279 Fliptile (二进制枚举+模拟)
- POJ -3279 Fliptile (二进制转换,枚举每行)
- POJ 3279 Fliptile(二进制枚举暴力)
- POJ 3279 Fliptile(状压搜索)
- POJ 3279Fliptile(状态枚举+搜索)
- 6. head 区的设置
- 关于QT下资源使用和资源占用内存过多的问题
- Failed to load platform plugin "windows"
- 第十三节 网络编程
- GRE写作必备句型
- POJ 3279 Fliptile (二进制+搜索)
- NSArray(不可变数组)、NSMutableArray(可变数组)、数组排序、NSNumber(多态:数值和对象互转)、NSValue(将结构体转换成对象)
- EJB笔记---JBoss 开发环境搭配
- 收藏网站14
- message sent to deallocated instance
- iOS开发 - CoreData框架 数据持久化
- Contains Duplicate II
- 扩展的欧几里得模板
- 收藏网站15