poj3279(dfs+二进制枚举思路)

题意转载自https://www.cnblogs.com/blumia/p/poj3279.html

题目属性:DFS

相关题目:poj3276

题目原文:
【desc】
Farmer John knows that an intellectually satisfied cow is a happy cow who will give more milk. He has arranged a brainy activity for cows in which they manipulate an M × N grid (1 ≤ M ≤ 15; 1 ≤ N ≤ 15) of square tiles, each of which is colored black on one side and white on the other side.

As one would guess, when a single white tile is flipped, it changes to black; when a single black tile is flipped, it changes to white. The cows are rewarded when they flip the tiles so that each tile has the white side face up. However, the cows have rather large hooves and when they try to flip a certain tile, they also flip all the adjacent tiles (tiles that share a full edge with the flipped tile). Since the flips are tiring, the cows want to minimize the number of flips they have to make.

Help the cows determine the minimum number of flips required, and the locations to flip to achieve that minimum. If there are multiple ways to achieve the task with the minimum amount of flips, return the one with the least lexicographical ordering in the output when considered as a string. If the task is impossible, print one line with the word "IMPOSSIBLE".
【In】
Line 1: Two space-separated integers: M and N
Lines 2.. M+1: Line i+1 describes the colors (left to right) of row i of the grid with N space-separated integers which are 1 for black and 0 for white 
【Out】
Lines 1.. M: Each line contains N space-separated integers, each specifying how many times to flip that particular location. 
【SampIn】
4 4
1 0 0 1
0 1 1 0
0 1 1 0
1 0 0 1
【SampOut】
0 0 0 0
1 0 0 1
1 0 0 1
0 0 0 0

【一句话题意】

给定长宽的黑白棋棋盘摆满棋子,每次操作可以反转一个位置和其上下左右共五个位置的棋子的颜色,求要使用最少翻转次数将所有棋子反转为黑色所需翻转的是哪些棋子(这句话好长...)。

【题目分析】

盯着奇怪的题目看了半天发现和奶牛没什么卵关系..奶牛智商高了产奶高是什么鬼说法...

这题刚开始被放到搜索的分类下了..然而这和搜索有什么关系..没经验所以想了各种和搜索沾边的方法,结果没想出解法,直到看了网上的题解,压根不是搜索啊有木有。

然后这题网上给的分类是简单题..简单题..蒟蒻跪了..

好了开始说解法。首先根据题目,每次操作都会影响到周围的“棋子”,而要使得每个1都被反转为0,那么我们就应当每次都反转1下方的棋子以改变1为0.

那么,当我们处理过1到n-1行的时候,前n-1行就都已经是0了,最后我们只需要检查最后一行是不是全部为0就可以检查这次的出操作是否正确了。如果正确且最小,那就存起来。最后输出,万事大吉。

当然,因为我们要改变第x行的1为0需要反转的是x+1行的位置。而这个整个规则是我们验证一组操作是否能达到目的所用的,那么我们需要在验证前先确定操作(没操作怎么验证..)。

于是根据规则内容可知,只需要能确认第一行的翻转情况,就能够推出下面所有的翻转情况并验证是否正确。于是需要做的就是枚举第一行的情况了。

【算法流程】

#include<stdio.h>
#include<string.h>
int n,m;
int count,min;
int s[20][20],s1[20][20];
int lg[20][20];
int cg(int a,int b)
{
int i,j;
s[a][b]=!s[a][b];
if(a-1>0)
s[a-1][b]=!s[a-1][b];
if(a+1<=n)
s[a+1][b]=!s[a+1][b];
if(b-1>0)
s[a][b-1]=!s[a][b-1];
if(b+1<=m)
s[a][b+1]=!s[a][b+1];
}
int do1(int a)
{
count=0;
int k=1;
int i,j;
memcpy(s,s1,sizeof(s));
memset(lg,0,sizeof(lg));
for(j=1;j<=m;j++)
{
if((a&(1<<(m-j)))>0) //记得a&1<<(m-j)要打括号,不然会是a&(1<<(m-j)>0)
{
cg(1,j),count++,lg[1][j]=1;
//printf("w%d %d\n",a,a&(1<<(m-j)));
}
}
for(i=1;i<n;i++)
for(j=1;j<=m;j++)
{
if(s[i][j]==1)
cg(i+1,j),count++,lg[i+1][j]=1;
}
for(j=1;j<=m;j++)
if(s[n][j]==1)
k=0;
//if(k==1)
//printf("%d %d\n",count,a);
return k;
}
int main()
{
int i,j,k;
while(scanf("%d%d",&n,&m)!=EOF)
{
min=n*m+1;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&s1[i][j]);
k=-1;
for(i=0;i<(1<<m);i++)//第一行翻动情况
{
if(do1(i)==1&&min>count)
{
min=count;
k=i;
//printf("%d\n",min);
}
}
if(k==-1)
printf("IMPOSSIBLE\n");
else
{
do1(k);
//printf("%d",k);
for(i=1;i<=n;i++)
{
j=1;
printf("%d",lg[i][j]);
for(j=2;j<=m;j++)
printf(" %d",lg[i][j]);
printf("\n");
}
}
}
return 0;
}

原文地址:https://www.cnblogs.com/cglongge/p/8538586.html

时间: 2024-08-10 06:09:13

poj3279(dfs+二进制枚举思路)的相关文章

UVa 818 切断圆环链(dfs+二进制枚举)

https://vjudge.net/problem/UVA-818 题意:有n个圆环,其中有一些已经扣在了一起.现在需要打开尽量少的圆环,使得所有圆环可以组成一条链,例如,有5个圆环,1-2,2-3,4-5,则需要打开一个圆环,如圆环4,然   后用它穿过圆环3和圆环5后再次闭合4,就可以形成一条链:1-2-3-4-5. 思路:从n个圆环中任意选择圆环,这就是枚举子集.所以这道题目可以用二进制枚举来做. 那么如何判断当前打开圆环是可行的呢?在去除打开的圆环后需要判断: ①:每个圆环的分支数都必

poj-3279 poj-1753(二进制枚举)

题目链接:http://poj.org/problem?id=3279 题目大意: 有一个m*n的棋盘(1 ≤ M ≤ 15; 1 ≤ N ≤ 15),每个格子有两面分别是0或1,每次可以对一个格子做一次翻转操作,将被操作的格子和与其相邻的周围4个格子都会进行翻转.问做少做多少次翻转可以将所有格子翻转成0,输出翻转方案(每个棋子的翻转次数).没有方案时输出"IMPOSSIBLE". Sample Input 4 4 1 0 0 1 0 1 1 0 0 1 1 0 1 0 0 1 Sam

CUGBACM_Summer_Tranning1 二进制枚举+模拟+离散化

整体感觉:这个组队赛收获还挺多的.自从期末考试以后已经有一个多月没有 做过组队赛了吧,可是这暑假第一次组队赛就找回了曾经的感觉.还挺不错的!继续努力!! 改进的地方:这次组队赛開始的时候题目比較难读懂,然后就感觉题目应该比較难吧,认为应该是区域赛难度的题目.尽管A题和B题自己都感觉能自己A的.可是可能对自己不太自信,所以让队友大帝敲了.要是当时自己敢敲一下的话,后续会更快的A掉吧. A题:二进制枚举 题目链接:https://icpcarchive.ecs.baylor.edu/external

51nod 1363 最小公倍数的和 欧拉函数+二进制枚举

1363 最小公倍数之和 题目来源: SPOJ 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 160 给出一个n,求1-n这n个数,同n的最小公倍数的和.例如:n = 6,1,2,3,4,5,6 同6的最小公倍数分别为6,6,6,12,30,6,加在一起 = 66. 由于结果很大,输出Mod 1000000007的结果. Input 第1行:一个数T,表示后面用作输入测试的数的数量.(1 <= T <= 50000) 第2 - T + 1行:T个数A[i](A[i] <

HDU 5025Saving Tang Monk BFS + 二进制枚举状态

3A的题目,第一次TLE,是因为一次BFS起点到终点状态太多爆掉了时间. 第二次WA,是因为没有枚举蛇的状态. 解体思路: 因为蛇的数目是小于5只的,那就首先枚举是否杀死每只蛇即可. 然后多次BFS,先从起点到第一把钥匙,不能往回走,要用VIS数组标记. 第二次从第一把钥匙走到第二把钥匙. 最后一次从最后一把钥匙走到终点即可. Tips 1: 在每次BFS过程中使用优先队列保证每次是最小步长的状态. Tips2 :使用二进制枚举蛇的状态 Tips3:首先使用DFS判断是否绝对有解,如果无解输出"

HDU 4309 Seikimatsu Occult Tonneru(最大流+二进制枚举)

http://acm.hdu.edu.cn/showproblem.php?pid=4309 题意: 有n个城市,每个城市有num[i]个居民,有敌人要进行地毯式轰击,居民们要逃到隧道去.现在有隧道,隧道允许无限个人通过,并且可以容纳w个人:有桥,可以允许无限个人通过,但是不能容纳人:还有一些破桥,修复这些破桥需要w花费,如果不修复,那么最多只能通过一人,如果修复了,那么可以通过无限个人.求出在能安全到达隧道的最大人数时的最小代价.(上述都是单向边) 思路:出题人也是有心了..在题目中有说破桥的

UVa818 Cutting Chains (二进制枚举)

链接:http://vjudge.net/problem/35523 分析:links记录初始圆环链的情况,然后二进制枚举编号为0~n-1的圆环哪个被打开了,一个圆环最多一个前驱和一个后继,所以judge判断如果有一个未打开的圆环同时和2个以上的未打开圆环相连就一定不能形成链,剪去.circle判断剩下的未打开圆环是否形成环,以及若未成环那么有多少条单链links_num,注意最后成链不用按顺序比如1->2->3...这样.然后判断一下打开的圆环数够不够把links_num条单链扣成一条链,若

POJ 2436 二进制枚举+位运算

题意:给出n头牛的得病的种类情况,一共有m种病,要求找出最多有K种病的牛的数目: 思路:二进制枚举(得病处为1,否则为0,比如得了2 1两种病,代号就是011(十进制就是3)),首先枚举出1的个数等于k的二进制数,然后跟所有的牛的代号一一比较,符合的           +1,找出其中和最大的:就是转换2进制麻烦,用位运算就好实现了,但是位运算不是很明白含义,明白了再补充: 知识点: 3 & 2 = 2,相同为1,不同为0, 011 & 010 = 010:(怎么利用的这个特点不明白):

UvaLive 6661 Equal Sum Sets 二进制枚举/DP

链接:http://vjudge.net/problem/viewProblem.action?id=49406 题意:根据给出的n,k,s求出n个数每个数都不大于k,和为s的序列(n个数每个都不同)的总情况数. 思路: 1.二进制枚举枚举出所有可能排列,并求和若和为s,则符合,否则不符合. 代码: #include<iostream> #include<set> #include<map> #include<queue> #include<cstri