POJ2965 状态压缩+BFS,DFS枚举,以及大牛的解法~

POJ2965 状态压缩+BFS,DFS枚举,以及大牛的解法~

和poj1753非常相似,这题用状态压缩+BFS同样可以解,状态压缩就是用二进制来表示一种状态。

这是我在1753上改的BFS+状态压缩代码:

 

//二进制+BFS写法
#include<iostream>
using namespace std;   //解决问题路径搜索

bool flag[65536];
int step[65536];
struct con
{
    int f;
    int k;
}connect[65536];
int ans[65536];
int qstate[65536];  //搜索状态
int top=0;
int rear=0;
void Init()
{
    int temp=0;
    char c;
    for(int i=0; i < 4; i++)
         for(int j = 0; j < 4; j++)
         {
             cin>>c;
             if('+' == c)
                 temp |= (1<<(i*4+j));
         }
    qstate[rear++] = temp;
     flag[temp]  = true;
}

int move(int state,int i)
{
    int temp=0;
    temp |= (1<<i);     //翻自己
    int j;
    for(j=i;(j+1)%4!=0;j++)//右
    temp |= (1<<(j+1));
    for(j=i;(j)%4!=0;j--)//左
    temp |= (1<<(j-1));
    for(j=i;(j-4)>=0;j=j-4)//上
    temp |= (1<<(j-4));
    for(j=i;(j+4)<16;j=j+4)//下
    temp |= (1<<(j+4));

    return (state ^ temp);
}

bool BFS()
 {
     while(rear > top)
     {
         int state = qstate[top++];
         for(int i=0; i < 16; i++)
         {
             int temp;
             temp = move(state,i);
             if(0 == state)
             {
                 cout<<step[state]<<endl;
                 int x=0;
                 for(int j=step[state]-1;j>=0;j--)
                 {
                     ans[j]=connect[x].k;
                     x=connect[x].f;
                 }
                 for(int j=0;j<step[state];j++)
                 {
                     cout<<(ans[j]/4)+1<<' '<<(ans[j]%4)+1<<endl;
                 }
                 return true;
             }
             else if(!flag[temp]) //防止重复搜索
             {
                 qstate[rear++] = temp;
                 flag[temp] = true;
                 step[temp] = step[state]+1;
                 connect[temp].f=state;
                 connect[temp].k=i;
             }
         }
     }

     return false;
 }
 int main(void)
 {
     Init();
     BFS();
     return 0;
 }

然后是参考网上DFS枚举的方法,以后将继续对DFS枚举进行理解。代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 10;
struct node
{
    int p, q;
}a[18];
int map[N][N], ans, flag;
void Change(int x, int y) //翻转函数
{
    int i;
    map[x][y] = !map[x][y];
    for (i = 1; i <= 4; ++i)
    {
        map[x][i] = !map[x][i];
        map[i][y] = !map[i][y];
    }
}
int Judge() //判断函数
{
    int i, j;
    for (i = 1; i <= 4; ++i)
    {
        for (j = 1; j <= 4; ++j)
        {
            if (map[i][j] == 0)
            {
                return 0;
            }
        }
    }
    return 1;
}
void DFS(int x, int y, int step)
{
    if (step == ans)
    {
        flag = Judge();//不能加if(flag),否则超时
        return ;
    }
    if (flag || x >= 5)
    {
        return ;
    }
    Change(x, y);
    if (y < 4)
    {
        DFS(x, y + 1, step + 1);
        a[step].p = x;
        a[step].q = y;
    }
    else                                //全部16枚举一遍
    {
        DFS(x + 1, 1, step + 1);
        a[step].p = x;
        a[step].q = y;
    }
    Change(x, y);                       //再原路返还
    if (y < 4)
    {
        DFS(x, y + 1, step);
    }
    else
    {
        DFS(x + 1, 1, step);
    }
}
int main()
{
    int i, j;
    char str;
    for (i = 1; i <= 4; ++i)
    {
        for (j = 1; j <= 4; ++j)
        {
            scanf("%c", &str);
            if (str == '-')
            {
                map[i][j] = 1;
            }
            else
            {
                map[i][j] = 0;
            }
        }
        getchar();//度掉回车
    }
    flag = 0;
    for (i = 0; i <= 16; ++i)
    {
        ans = i;
        DFS(1, 1, 0);
        if (flag)
        {
            break;
        }
    }
    if (flag)
    {
        printf("%d\n", ans);
        for (i = 0; i < ans; ++i)
        {
            printf("%d %d\n", a[i].p, a[i].q);
        }
    }
    return 0;
}

 

 

 

再最后就是网上大神的算法,找到其中巧妙的规律。这也提醒我以后多将过程展示出来可从中发现重要的信息!:

/*既然说要把所有的开关变成是打开的话,那么怎么样才能做而且又不影响其他的布局呢?如果没遇到一个‘+’即关闭的开关,我们就把这个开关所在行和列包括它本身(本身只操作一次)都操作一次的话。那么可以计算它本身的状态变化次数为7,其同在一行和一列的元素则状态变化为4,余下的状态转化都是2.可以得到这个方法可以在不影响其它元素的状态下将关闭的开关打开(因为偶数次对状态实际上是没有影响的)。所有我们只要遇到一个'+'就重复上面的操作,而且用一个数组记录下每个元素被操作的次数。最后扫描一次数组,操作次数为奇数的就是我们需要操作的点(偶数次操作相当于没有操作)。
代码:*/
#include<stdio.h>
long m[5][5] ;
void dose(int x,int y){//没操作一次就对元素标记数组加一
for(int i = 1;i<=4;i++){
m[x][i]++ ;
if(i!=x)m[i][y]++ ;
}
}
int steps(){//计算需要操作的次数
int c = 0 ;
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
if(m[i][j]%2) c++ ;
return c ;
}
int main()
{
int
char c ;
for(i = 1 ; i <= 4 ; i++){
for(j = 1 ; j <= 4 ; j++){
scanf("%c",&c) ;
if(c=='+') dose(i,j) ;
}
getchar() ;
}
printf("%d\n",steps()) ;
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
if(m[i][j]%2)//遇到是奇数的就打印出来
printf("%d %d\n",i,j) ;
return 0 ;
}

 

当然还有一种纯纯的暴力枚举也能过。。用16个for语句的枚举。。

 

转载于:https://www.cnblogs.com/amourjun/archive/2013/03/15/5134220.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/110191.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • knox芯片_推广代理平台

    knox芯片_推广代理平台使用knox进行正向和反向代理,并且进行一些权限认证,使用起来很方便,特别是对于NiFi的相关权限认证(ldap),所以本章节讲下我使用knox代理的服务,以及相关的一些配置选项。/gateway/san在这里面的每个xml被视为一个集群,集群中可以有多个service。topologies目录下的xml文件才会被加载,如果下面有文件夹不会继续查找。默认已经帮我们把所有的配置好了,所以只需要更改下面service的ip就行。这里创建了一个master秘钥,是给knoxgateway的秘钥。

    2025年7月25日
    3
  • php 对象转json_php json解析

    php 对象转json_php json解析在PHP中,可以使用json_decode()函数来将json字符串转换为PHP对象。json_decode()函数用于解码JSON字符串,把json字符串转成对象或数组,默认转成对象;设置函数的第二个参数为true,则可转成关联数组。json_decode()函数是PHP中的内置函数,用于对JSON格式的字符串进行解码,可以将JSON格式的字符串转换为PHP变量(object或array)。…

    2022年10月7日
    5
  • 配置注册表数据库损坏

    配置注册表数据库损坏

    2021年9月29日
    54
  • spring aop 切入问题

    spring aop 切入问题spring aop 切入问题

    2022年4月20日
    35
  • HTTPS能有效保护用户隐私

    HTTPS就等于HTTP加上TLS(SSL),HTTPS协议的目标主要有三个:http://hovertree.com/menu/webfront/数据保密性。保证内容在传输过程中不会被第三方查看

    2021年12月24日
    42
  • c语言韦达定理求方程解,高一上韦达定理,高次,多元方程解法.doc

    c语言韦达定理求方程解,高一上韦达定理,高次,多元方程解法.doc实用文档PAGE文案大全一元二次方程根与系数关系(韦达定理),多元方程解法,高次方程解法一元二次方程根与系数的关系现行初中数学教材主要要求学生掌握一元二次方程的概念、解法及应用,而一元二次方程的根的判断式及根与系数的关系,在高中教材中的二次函数、不等式及解析几何等章节有着许多应用.本节将对一元二次方程根的判别式、根与系数的关系进行阐述.一)、一元二次方程的根的判断式一元二次方程,用配方法将其变形为…

    2025年7月24日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号