P1985 [USACO07OPEN]翻转棋

题目链接:

翻转棋

题目分析:

先状压/\(dfs\)枚举第一排状态,然后在每个\(1\)下面翻,即确定了第一排就确定了后面的状态
最后验证一下最后一排是不是全0即可

代码:

#include<bits/stdc++.h>
#define N 50
using namespace std;
inline int read() {
    int cnt = 0, f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
    while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + (c ^ 48); c = getchar();}
    return cnt * f;
}
int mapp[N][N], m, n, cnt, ans[N][N], res = (1 << 30);
bool vis[N][N], flag;
void rev(int x, int y) {
    mapp[x][y] ^= 1;
    mapp[x][y - 1] ^= 1;
    mapp[x - 1][y] ^= 1;
    mapp[x][y + 1] ^= 1;
    mapp[x + 1][y] ^= 1;
}
void cpy() {
    for (register int i = 1; i <= m; ++i)
        for (register int j = 1; j <= n; ++j) ans[i][j] = vis[i][j];
}
void work() {
    for (register int i = 2; i <= m; ++i)
        for (register int j = 1; j <= n; ++j) if (mapp[i - 1][j]) rev(i, j), vis[i][j] = 1, ++cnt;
    flag = 0;
    for (register int i = 1; i <= m; ++i)
        for (register int j = 1; j <= n; ++j) if (mapp[i][j]) flag = 1;
    if (!flag) if (cnt < res) cpy(), res = cnt;

    for (register int i = 2; i <= m; ++i)
        for (register int j = 1; j <= n; ++j) if (vis[i][j]) rev(i, j), vis[i][j] = 0, --cnt;
}
void dfs_(int k) {
    if (!k) {work(); return;}
    dfs_(k - 1), rev(1, k), vis[1][k] = 1, ++cnt;
    dfs_(k - 1), rev(1, k), vis[1][k] = 0, --cnt;
}
int main() {
    m = read(), n = read();
    for (register int i = 1; i <= m; ++i)
        for (register int j = 1; j <= n; ++j) mapp[i][j] = read();
    dfs_(n);
    if (res == (1 << 30)) return printf("IMPOSSIBLE"), 0;
    for (register int i = 1; i <= m; ++i) {
        for (register int j = 1; j <= n; ++j) printf("%d ", ans[i][j]);
        printf("\n");
    }
    return 0;
}#include<bits/stdc++.h>
#define N 50
using namespace std;
inline int read() {
    int cnt = 0, f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
    while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + (c ^ 48); c = getchar();}
    return cnt * f;
}
int mapp[N][N], m, n, cnt, ans[N][N], res = (1 << 30);
bool vis[N][N], flag;
void rev(int x, int y) {
    mapp[x][y] ^= 1;
    mapp[x][y - 1] ^= 1;
    mapp[x - 1][y] ^= 1;
    mapp[x][y + 1] ^= 1;
    mapp[x + 1][y] ^= 1;
}
void cpy() {
    for (register int i = 1; i <= m; ++i)
        for (register int j = 1; j <= n; ++j) ans[i][j] = vis[i][j];
}
void work() {
    for (register int i = 2; i <= m; ++i)
        for (register int j = 1; j <= n; ++j) if (mapp[i - 1][j]) rev(i, j), vis[i][j] = 1, ++cnt;
    flag = 0;
    for (register int i = 1; i <= m; ++i)
        for (register int j = 1; j <= n; ++j) if (mapp[i][j]) flag = 1;
    if (!flag) if (cnt < res) cpy(), res = cnt;

    for (register int i = 2; i <= m; ++i)
        for (register int j = 1; j <= n; ++j) if (vis[i][j]) rev(i, j), vis[i][j] = 0, --cnt;
}
void dfs_(int k) {
    if (!k) {work(); return;}
    dfs_(k - 1), rev(1, k), vis[1][k] = 1, ++cnt;
    dfs_(k - 1), rev(1, k), vis[1][k] = 0, --cnt;
}
int main() {
    m = read(), n = read();
    for (register int i = 1; i <= m; ++i)
        for (register int j = 1; j <= n; ++j) mapp[i][j] = read();
    dfs_(n);
    if (res == (1 << 30)) return printf("IMPOSSIBLE"), 0;
    for (register int i = 1; i <= m; ++i) {
        for (register int j = 1; j <= n; ++j) printf("%d ", ans[i][j]);
        printf("\n");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/kma093/p/11620134.html

时间: 2024-11-02 16:15:02

P1985 [USACO07OPEN]翻转棋的相关文章

[题解] luogu P1985 [USACO07OPEN]翻转棋

题面 今天学搜索,正好水一发以前做的这道毒瘤题 话说这道题做了我一天,别人都是各种优化,不超100行 天真的我硬核刚了220行,全程0优化水过 但其实不用这么长,我有的函数写的有点重复了( 思路: 显然是dfs,一行一行的来 搜到[i, j]时(i > 1),看[i - 1, j]是否为黑,是的话就翻转[i, j], 也就是说搜完当前行就要保证上一行的棋全都翻成了白色 当搜到最后一行时, 既要保证上一行翻成白色,还要保证自己也都翻成白色, 最后还要特判一下最后两个的翻转. 当时年少轻狂,我想着层

P1985 [USACO07OPEN]翻转棋 题解

CSDN同步 原题链接 简要题意: 给定一个 \(01\) 棋盘,每次可以翻转一个"十"字形(即一个格子连同它四方向的相邻格子,出界则不翻).求在哪些格子上翻转(十字形的中心)可以使得 翻转后全 \(0\) 且 方案字典序最小 . 首先 \(n,m \leq 15\),本着面向数据范围做题的原理,分析算法. 算法一 枚举翻转哪些格子进行验证. 时间复杂度:\(O(2^{n \times m} \times n \times m)\),难以接受这样的爆炸性复杂度. 算法二 需要我们分析一

搜索专讲

搜索专讲 Tags:搜索 https://www.zybuluo.com/xzyxzy/note/1058215 前言 做一个专题肯定是要花点时间的 但是哇,搜索怎么这么多内容?!WTF?! 好吧慢慢刷,待四五月份左右出pdf或ppt的讲义吧 先把题目放上,大家愿意的和我一起做吧 题目 李老师给了一个包 广搜 [x] ?POJ1426-Find The Multiple https://vjudge.net/problem/POJ-1426 [x] POJ2251-Dungeon Master

POJ1753Flip Game(DFS + 枚举)

Flip Game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 37050   Accepted: 16122 Description Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the

[嵌入式中国 http://www.armchina.cn/ 转帖]既是老师又是师兄的临别箴言

转自:http://blog.chinaunix.net/uid-20543672-id-94273.html 他在评阅我们毕设论文时候就经常为计算机学生现状感到痛心疾首,在最后一次论文的 修订中收到老师最长的一封邮件,洋洋洒洒三千字有余.一口气读完,感慨颇多,特别是 读到96级和03级对比之处惊讶之余,心中生出感动的情绪来.在这个时候得到老师宝贵 的“批评”,我想我是幸运的,因为之后的路更长.   在此,我再次谢谢老师,谢谢这段时间在实验室遇到的其它老师和学长,各种教诲和帮 助铭记于心.经过老

人机对战-黑白棋

先大致了解一下黑白棋: 规则 如果玩家在棋盘上没有地方可以下子,则该玩家对手可以连下.双方都没有棋子可以下时棋局结束,以棋子数目来计算胜负,棋子多的一方获胜. 在棋盘还没有下满时,如果一方的棋子已经被对方吃光,则棋局也结束.将对手棋子吃光的一方获胜. 翻转棋类似于棋盘游戏"奥赛罗 (Othello)",是一种得分会戏剧性变化并且需要长时间思考的策略性游戏. 翻转棋的棋盘上有 64 个可以放置黑白棋子的方格(类似于国际象棋和跳棋).游戏的目标是使棋盘上自己颜色的棋子数超过对手的棋子数.

黑白棋

一般棋子双面为黑白两色,故称"黑白棋".因为行棋之时将对方棋子翻转,变为己方棋子,故又称"翻转棋"(Reversi).棋子双面为红.绿色的称为"苹果棋". 棋子:黑白棋棋子每颗由黑白两色组成,一面白,一面黑,共64个(包括棋盘中央的4个).棋子呈圆饼形. 棋盘:黑白棋棋盘由64格的正方格组成,游戏进行时棋子要下在格内.棋盘可分为"角"."边"以及"中腹".现今的棋盘多以8x8较为普遍.

BestCoder Round #90

有生以来第一场在COGS以外的地方打的比赛.挂成dog了. 主要是没有经验,加之代码能力过弱.还有最后的瞎hack三次,Too Young Too Simple...... 言归正传. (抄一发题解先) T1 Kblack loves flag 用两个布尔数组分别维护每个行/列是否被插过旗帜,最后枚举每一行.列统计答案即可.空间复杂度O(n+m),时间复杂度O(n+m+k). T2 dingyeye loves stone 设根节点的深度为0,将所有深度为奇数的节点的石子数目xor起来,则先手必

Windows的历史zt

原文地址:http://windows.microsoft.com/zh-CN/windows/history#T1=era0 1975–1981:Microsoft 起步 Microsoft 联合创始人 Paul Allen(左)和 Bill Gates 当时是二十世纪七十年代, 人们的工作主要依赖于打印机. 如果需要复制文档,则可能会使用油印机或复写纸. 很少有人听说过微型计算机,但是两个年轻的计算机发烧友 Bill Gates 和 Paul Allen 却发现个人计算是通向未来的道路. 1