Fliptile POJ - 3279 (状态压缩+枚举) && Flip Game POJ - 1753(状态压缩+bfs暴力)
2017-05-22 16:20
513 查看
看Fliptile前我们先做Flip Game,后者相当于是前者的简化版
由于我们的状态仅仅是一连串01数,那我们为什么不用二进制的数去表示它呢?这就是我理解的状态压缩了
一个int型的数就可以存下32位,long long就能存下64位
我们回到这题, 假如某个状态我们用数 int x 表示,那么我们想翻转第i位,就可以用位运算里的异或(^)
就酱 x ^= (1 << i)
这样我们就没法像上一题那样一个数存下状态。。。就算存得下时间也不够。。。
(这题在我刚学算法的时候真的绞尽脑汁也写不出来哇,卡到我会状态压缩。。。已经几个月了。。Orz)
这时候就需要我们思考一下了。。。首先我们得发现第m行可以通过第m+1行的反转而全部转换成0(这题要全0)
以此类推,我们会惊奇地发现原来第一行的反转就决定了下面所有行该如何翻转,如果按照之前所说的翻转方法,最后一行如果不能变成全0那第一行的翻法就是错的否则就行了,不过还得找最翻转次数最少的。。。这时候我们只要枚举第一行就行啦,最多15,又回到上一题啦
Flip Game
题目链接
https://vjudge.net/problem/16122/origin题目大意
给你4*4的01矩阵,当你翻转一个数时,其四周的所有数都取反,问你最少经过多少次翻转可以使所有数都为0或1核心思想
由于矩阵仅仅是4*4的固定规模,我们只需用一个int型的数进行状态压缩就能存下当前的状态,然后用bfs暴力跑出最快到达全0或1的状态,最多就2^16次QAQ状态压缩
这里细致讲一下状态压缩由于我们的状态仅仅是一连串01数,那我们为什么不用二进制的数去表示它呢?这就是我理解的状态压缩了
一个int型的数就可以存下32位,long long就能存下64位
我们回到这题, 假如某个状态我们用数 int x 表示,那么我们想翻转第i位,就可以用位运算里的异或(^)
就酱 x ^= (1 << i)
代码
#include<cstdio> #include<iostream> #include<cstring> #include<string> #include<queue> #include<algorithm> using namespace std; const int M = 65536; bool vis[M]; char mp[5][5]; int p = 0; struct P{ int x, r; }; queue<P>q; int flip(int xx, int ii)//模拟翻转的函数,x是状态,ii是翻转位置 { int x = ii / 4, y = ii % 4; xx ^= (1 << ii); if(x > 0) xx ^= (1 << (ii -4)); if(x < 3) xx ^= (1 << (ii + 4)); if(y > 0) xx ^= (1 << (ii - 1)); if(y < 3) xx ^= (1 << (ii + 1)); return xx; } void bfs()//bfs来遍历所有翻转所有情况 { memset(vis, 0, sizeof(vis)); while(!q.empty())q.pop(); q.push(P{p, 0}); vis[p] = 1; while(!q.empty()) { P nop = q.front(), nxp; q.pop(); if(nop.x == 0 || nop.x == 65535)//全零或全一,全一就是2^16 -1 { printf("%d\n", nop.r); return ; } else { for(int i=0; i<16; ++i) { nxp.x = flip(nop.x, i); if(!vis[nxp.x]) { nxp.r = nop.r + 1; q.push(nxp); vis[nxp.x] = 1; } } } } puts("Impossible"); return ; } int main() { for(int i = 0; i<4; ++i) scanf("%s", mp[i]); int w = 0; for(int i=0; i<4; ++i) { for(int j=0; j<4; ++j) { if(mp[i][j] == 'b') { p ^= (1<<(w)); } w++; } } bfs(); return 0; }
Fliptile
题目链接
https://vjudge.net/problem/17522/origin题目大意
这题就是上一题的升级版哇,不是4*4的01矩阵啦,而是让你自行输入矩阵行和列。。。最大15*15。。Orz这样我们就没法像上一题那样一个数存下状态。。。就算存得下时间也不够。。。
(这题在我刚学算法的时候真的绞尽脑汁也写不出来哇,卡到我会状态压缩。。。已经几个月了。。Orz)
这时候就需要我们思考一下了。。。首先我们得发现第m行可以通过第m+1行的反转而全部转换成0(这题要全0)
以此类推,我们会惊奇地发现原来第一行的反转就决定了下面所有行该如何翻转,如果按照之前所说的翻转方法,最后一行如果不能变成全0那第一行的翻法就是错的否则就行了,不过还得找最翻转次数最少的。。。这时候我们只要枚举第一行就行啦,最多15,又回到上一题啦
代码
#include<cstdio> #include<string> #include<queue> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int m, n, cnt; bool mp[20][20], temp[20][20], f[20][20]; int dx[5] = {1, 0, -1, 0}, dy[5] = {0, 1, 0, -1}; void flip(int x, int y)//模拟翻转函数 { ++cnt; f[x][y] = 1; temp[x][y] = !temp[x][y]; for(int k=0; k<4; ++k) { if(0 <= x + dx[k] && x +dx[k] <m && 0<= y+dy[k] && y+dy[k] <= n) temp[x+dx[k]][y+dy[k]] = !temp[x+dx[k]][y+dy[k]]; } } bool check(int ii)//判断枚举出的第一行状态能否使最后变全0 { cnt = 0; memcpy(temp, mp, sizeof(temp)); for(int i=0; i<n; ++i) { if(ii & (1 <<(n - 1 - i) ) ) flip(0, i); } for(int i=0; i<m-1; ++i) { for(int j=0; j<n; ++j) { if(temp[i][j]) flip(i+1, j); } } for(int j=0; j<n; ++j) { if(temp[m-1][j]) return false; } return true; } int main() { while(~scanf("%d%d", &m, &n)) { for(int i=0; i<m; ++i) { for(int j=0; j<n; ++j) scanf("%d", &mp[i][j]); } int mn = 1 << n, ans = m*n+1, p = -1;//ans理论最大就m*n,但是初始化成m*n就wa了,+1就过了,求大佬解释 for(int i=0; i < mn; ++i) { if(check(i) && (cnt<ans) ) { ans = cnt; p = i; } } memset(f, 0, sizeof(f)); if(p >= 0) { check(p); for(int i=0; i<m; ++i) { for(int j=0; j<n; ++j) { printf("%d%c",f[i][j], (j == n-1) ? '\n' : ' ');//逼格超高的矩阵输出 } } } else puts("IMPOSSIBLE"); } }
相关文章推荐
- POJ 3279 Fliptile(状态压缩+暴力)
- Flip Game(poj1753,状态压缩+暴力枚举)
- 【状态压缩枚举】poj 1753 Flip Game
- POJ 3279 Fliptile(枚举状态)
- POJ 3279 (状态压缩暴力枚举)
- POJ 3279 Fliptile(二进制枚举暴力)
- Fliptile POJ - 3279 (暴力搜索)
- POJ-1753 Flip Game【暴力枚举】
- HDOJ 1079 && POJ 1082 Calendar Game (博弈: 暴力枚举所有状态的P\N)
- 【BFS+状态压缩】-POJ-1753-Flip Game
- POJ-1753 Flip Game 枚举 状态压缩
- POJ 3279 Fliptile(反转+二进制枚举)
- poj 1753 Flip Game(bfs状态压缩 或 dfs枚举)
- POJ 1753 Flip Game(枚举+状态压缩BFS)
- 状态压缩+枚举 POJ 3279 Fliptile
- POJ 1753 Flip Game BFS+位压缩状态
- poj 1753 Flip Game 枚举(bfs+状态压缩)
- POJ 3279 Fliptile(暴力)
- POJ 1753 Flip Game 暴力搜索(dfs加枚举)
- POJ 1753 Flip Game 状态压缩 枚举