POJ3185 The Water Bowls

  题目大意: 奶牛有20只碗摆成一排,用鼻子顶某只碗的话,包括左右两只在内的一共三只碗会反向,现在给出碗的初始状态,问至少要用鼻子顶多少次才能使所有碗都朝上

  一开始试了一下dfs,由于对dfs还是不太熟悉,先是用了一个数组b[i]来储存翻转后的状态,后来发现这个搜索的状态虽然类似背包,要么翻转,要么不翻转,但是翻转某个碗以后会对其他的也造成影响,所以这样这样做就错了,可以只用原来的数组就ok了

在上述问题解决后,又因为胡乱剪枝导致wa了几次,一开始我想先对a[0]和a[19]进行判断是否为1,来确定是否需要翻转,这样的话a[19]那儿的1可能是翻转后形成的,这是进行翻转就回不到原来的状态,导致没法遍历2^n而wa,同时,对a[0]是否为1的判断也是错的,因为a[0]等于1时也可以通过翻转a[1]来实现a[0]=0的要求,a[19]=1也可翻转下一次的a[18].

不用任何优化顶多2^20(10的6次方左右),也可以过,我最后是250ms左右过的.

  dfs代码:(毕竟dfs的题做的比较少,也就先用dfs来练手了)(先翻转再翻回来的dfs才是对的)

  

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <sstream>
#include <fstream>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define in(n) scanf("%d",&(n))
#define in2(x1,x2) scanf("%d%d",&(x1),&(x2))
#define inll(n) scanf("%I64d",&(n))
#define inll2(x1,x2) scanf("%I64d%I64d",&(x1),&(x2))
#define inlld(n) scanf("%lld",&(n))
#define inlld2(x1,x2) scanf("%lld%lld",&(x1),&(x2))
#define inf(n) scanf("%f",&(n))
#define inf2(x1,x2) scanf("%f%f",&(x1),&(x2))
#define inlf(n) scanf("%lf",&(n))
#define inlf2(x1,x2) scanf("%lf%lf",&(x1),&(x2))
#define inc(str) scanf("%c",&(str))
#define ins(str) scanf("%s",(str))
#define out(x) printf("%d\n",(x))
#define out2(x1,x2) printf("%d %d\n",(x1),(x2))
#define outf(x) printf("%f\n",(x))
#define outlf(x) printf("%lf\n",(x))
#define outlf2(x1,x2) printf("%lf %lf\n",(x1),(x2));
#define outll(x) printf("%I64d\n",(x))
#define outlld(x) printf("%lld\n",(x))
#define outc(str) printf("%c\n",(str))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define mem(X,Y) memset(X,Y,sizeof(X));
typedef vector<int> vec;
typedef long long ll;
typedef pair<int,int> P;
const int dx[]={,,-,},dy[]={,,,-};
const int INF=0x3f3f3f3f;
const ll mod=1e9+;
ll powmod(ll a,ll b) {ll res=;a%=mod;for(;b;b>>=){if(b&)res=res*a%mod;a=a*a%mod;}return res;}
const bool AC=true; int a[],b[],ans;
bool flag;
void dfs(int i,int cnt){
if(i==){
flag=true;
rep(j,,){
if(a[j]==) {
flag=false;
break;
}
}
if(flag){
ans=min(ans,cnt);
}
return;
}
else if(i==){
a[i]=!a[i];
a[i+]=!a[i+];
dfs(i+,cnt+);
a[i]=!a[i];
a[i+]=!a[i+];
dfs(i+,cnt); //此处也不用判断是否为1来剪枝,否则会wa
}
else if(i==){
a[i]=!a[i];
a[i-]=!a[i-];
dfs(i+,cnt+);
a[i]=!a[i];
a[i-]=!a[i-];
dfs(i+,cnt); //不要乱剪枝,否则翻转不回来
}
else{
a[i]=!a[i];
a[i-]=!a[i-];
a[i+]=!a[i+];
dfs(i+,cnt+);//先翻转,再翻回来
a[i]=!a[i];
a[i-]=!a[i-];
a[i+]=!a[i+];
dfs(i+,cnt);
}
return ;
}
int main(){
rep(i,,) {
in(a[i]);
}
ans=INF;
dfs(,);
out(ans);
return ;
}

下面是反转法:考虑某个碗,翻转下一个碗.

       如果某个碗是0,则这个碗不需要考虑,继续考虑下一个碗,不断向前推进区间;

       如果某个碗是1,则必须翻转下一个碗,继续考虑下一个碗,不断向前推进区间;

       这样复杂度就是O(n),类似尺取法的思想;

        从对称性的角度考虑问题

   wa的注意了,不要通过判断a[0]=0来确定是否需要反转a[0],这样是错的如下面的情况: 0 0 1 0 0 0 0 0.....后面全是0,这时如果反转a[0]需要2步,不翻转a[0]需要12步(因为这个wa了n次),

    所以不管a[0]为什么值都要尝试一下是否需要反转a[0],从对称性来看,从左向右翻转,a[19]要么翻转,要么不翻转,

    所以翻转法有两种实现方式:从左向右翻转两次(反转a[0]或者不反转a[0])

                从左向右翻转一次(不翻转a[0]),再从右向左翻转一次(不翻转a[19]);(让某个碗翻转的方式有两种)

 从左向右翻转两次(反转a[0]或者不反转a[0])

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[],b[];
void turn(int i){
b[i-]^=;
b[i]^=;
if(i<) b[i+]^=;
}
int main(){
int cnt1=,cnt2=;
for(int i=;i<;i++)
scanf("%d",&a[i]);
//反转b[0];
memcpy(b,a,sizeof(a));
b[]^=;
b[]^=;
cnt1++; //此处要加1
for(int i=;i<;i++){
if(b[i]){
turn(i+);//考虑某个碗,反转其后面的碗
cnt1++;
}
}
if(b[]) cnt1=0x3f3f3f3f;
//不反转b[0];
memcpy(b,a,sizeof(a));
for(int i=;i<;i++){
if(b[i]){
turn(i+);//考虑某个碗,反转其后面的碗
cnt2++;
}
}
if(b[]) cnt2=0x3f3f3f3f;
printf("%d\n",min(cnt1,cnt2));
return ;
}

从左向右翻转一次(不翻转a[0]),再从右向左翻转一次(不翻转a[19]);

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[],b[];
void turn1(int i){
b[i-]^=;
b[i]^=;
if(i<) b[i+]^=;
}
void turn2(int i){
a[i+]^=;
a[i]^=;
if(i>) a[i-]^=;
}
int main(){
int cnt1=,cnt2=;
for(int i=;i<;i++)
scanf("%d",&a[i]);
memcpy(b,a,sizeof(a));
for(int i=;i<;i++){
if(b[i]){
turn1(i+);//考虑某个碗,反转其后面的碗
cnt1++;
}
}
if(b[]) cnt1=0x3f3f3f3f;
for(int i=;i>;i--){
if(a[i]){
turn2(i-);//考虑某个碗,反转其前面的碗
cnt2++;
}
}
if(a[]) cnt2=0x3f3f3f3f;
printf("%d\n",min(cnt1,cnt2));
return ;
}

POJ3185 The Water Bowls(反转法or dfs 爆搜)的更多相关文章

  1. HDU 4403 A very hard Aoshu problem(dfs爆搜)

    http://acm.hdu.edu.cn/showproblem.php?pid=4403 题意: 给出一串数字,在里面添加一个等号和多个+号,使得等式成立,问有多少种不同的式子. 思路: 数据量比 ...

  2. POJ3185 The Water Bowls 反转(开关)

    Description The cows have a line of 20 water bowls from which they drink. The bowls can be either ri ...

  3. [Gauss]POJ3185 The Water Bowls

    题意:反正就是要给的一串01的变成全0 能影响自己和左右 最少需要几步 01方程组 异或解 ][]; // 增广矩阵 ]; // 解 ]; // 标记是否为自由未知量 int n; void debu ...

  4. 【BZOJ-1060】时态同步 树形DP (DFS爆搜)

    1060: [ZJOI2007]时态同步 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2101  Solved: 595[Submit][Statu ...

  5. hdu 5506 GT and set(dfs爆搜)

    Problem Description You are given N sets.The i−th set has Ai numbers.You should divide the sets into ...

  6. 火车进栈(进出栈的模拟,dfs爆搜)

    这里有n列火车将要进站再出站,但是,每列火车只有1节,那就是车头. 这n列火车按1到n的顺序从东方左转进站,这个车站是南北方向的,它虽然无限长,只可惜是一个死胡同,而且站台只有一条股道,火车只能倒着从 ...

  7. hdu 4770(枚举 + dfs爆搜)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4770 思路:由于最多只有15个".",可以直接枚举放置的位置,然后判断是否能够全部 ...

  8. Ancient Go---hdu5546(dfs爆搜CCPC题目)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5546 题意就是两个人下围棋,问在下一颗x是否能杀死o,'.'是空位子: 枚举所有的点,判断是否合法即可 ...

  9. 【csp模拟赛2】 爆搜 方格加数

    [题目描述] xyz1048576正在玩一个关于矩阵的游戏. 一个n*m的矩阵,矩阵中每个数都是[1,12]内的整数.你可以执行下列两个操作任意多次: (1)指定一行,将该行所有数字+1. (2)指定 ...

随机推荐

  1. Delphi控件的透明与不透明(要挨个解释一下原因),对InvalidateControl的关键理解

    procedure TForm1.Button3Click(Sender: TObject);begin if (csOpaque in ControlStyle) then ShowMessage( ...

  2. 汉字转拼音的Java类库:JPinyin

    JPinyin是一个汉字转拼音的Java开源类库,在PinYin4j的功能基础上做了一些改进. [JPinyin主要特性]1.准确.完善的字库:Unicode编码从4E00-9FA5范围及3007(〇 ...

  3. 动态规划(二维背包问题):UVAoj 473

     Raucous Rockers  You just inherited the rights to n previously unreleased songs recorded by the pop ...

  4. Divide Two Integers —— LeetCode

    Divide two integers without using multiplication, division and mod operator. If it is overflow, retu ...

  5. sublime text3安装SublimeREPL--解决不能运行input()的问题

    原文地址:http://blog.chinaunix.net/uid-12014716-id-4269991.html 一.安装包管理器(如果已经安装可以忽略) 1.简单的安装方法:使用Ctrl+`快 ...

  6. 数据结构典型算法的VC实现(袁辉勇)

    1. 迷宫问题求解 #include <stdio.h> #define m 8 //迷宫内有8列 #define n 8 //迷宫内有8行 #define MAXSIZE 100//栈尺 ...

  7. TXT四则运算计算器 后日谈

    经过了软件工程第一个个人项目——<<四则运算器>>的开发后,对软件开发有了新的认识.题目中并没有明确说明对小数和负数是否应该提供支持.在第一个项目结束后,第二个项目则是针对上一 ...

  8. Marzoni(玛佐尼)意大利顶级西服面料之一_HollandandSherry_新浪博客

    Marzoni(玛佐尼)意大利顶级西服面料之一_HollandandSherry_新浪博客 Marzoni(玛佐尼)意大利顶级西服面料之一 (2013-01-08 17:30:04) 转载▼

  9. MapReduce多用户任务调度器——容量调度器(Capacity Scheduler)原理和源码研究

    前言:为了研究需要,将Capacity Scheduler和Fair Scheduler的原理和代码进行学习,用两篇文章作为记录.如有理解错误之处,欢迎批评指正. 容量调度器(Capacity Sch ...

  10. vue-cli 中 使用vue-resource 输出后台数据

    阅读此文前,请了解vue-cli 组件如何使用  http://www.cnblogs.com/pearl07/p/6252116.html 1,mock(模拟)后台数据(新建data.Json文件) ...