poj 2965

题目大意:输入为4*4矩阵,每个位置代表一个开关,只包含‘+’和‘-’,‘+’代表关闭,‘-’代表打开,矩阵所有位置都为‘-’表示通过,每次打开某一位置开关,它所在行和列开关都会打开,输出通过的最少步骤,并输出步骤;

思路:改变一个开关奇数次效果都是一样的,相当于改变一次开关状态,偶数次相当于没动开关,且改变开关状态的顺序对结果没有影响(这一点自行论证);所以对于一共改变开关状态的次数,共有16种可能,假设某次通过一共改变i个开关状态,则该次数下又有C(n,16)种可能;所以可以采用暴力枚举+DFS求解;
代码如下:
#include<cstdio>
#include<cstring>


using namespace std;


const int maxn = 6;//只用到了中间4个;
char state[maxn][maxn];//当前矩阵状态
int wayr[maxn],wayc[maxn];//分别记录最短步骤的开关的行和列;
int step,flag;//由于step是从小到大枚举,做成全局变量,flag用来标记是否达到全开状态;


bool judge()//判断是否达到全开状态
{
    char c='-';
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
        {
            if(state[i][j]!=c) return 0;
        }
    return 1;
}
void change(int x,int y)//用于单一开关改变状态;
{
    if(state[x][y]=='+') state[x][y]='-';
    else state[x][y]='+';
}
void turn(int x,int y)//用于改变当前开关所在行列开关的状态;
{
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
        {
            if(i==x||j==y) change(i,j);
        }
}
void dfs(int x,int y,int deep)
{
    if(deep==step)
    {
        flag=judge();
        return;
    }
    if(x>4||flag) return;//flag的目的是:当发现最少次数方式并返回结束该次dfs后,又进入其他dfs,这是就可以靠判全局变量flag迅速返回;
    wayr[deep]=x;
    wayc[deep]=y;//记录开关坐标编号,由于用deep做下表,所以不必担心turn还原后还存留,因为会被新的覆盖掉,注意存放路径的数组下标一般都跟某参数关联,该参数往往与题目密切相关;
    turn(x,y);
    if(y<4)//如果y==4说明该行已经枚举完毕,让x+1,y=1,进行下一行枚举;总之整个过程就是从(1,1)开始按行枚举;
    {
        dfs(x,y+1,deep+1);
        turn(x,y);//还原以便于下一次dfs;
        dfs(x,y+1,deep);
    }
    else
    {
        dfs(x+1,1,deep+1);
        turn(x,y);
        dfs(x+1,1,deep);
    }
    return;
}
int main()
{
    for(int i=1;i<=4;i++)
    {
        for(int j=1;j<=4;j++)
            scanf("%c",&state[i][j]);
        getchar();//没有就不对,我不知为啥;
    }
    flag=0;
    for(step=1;step<=16;step++)
    {
        dfs(1,1,0);//从编号为(1,1)的开关开始枚举;
        if(flag) break;
    }
    printf("%d\n",step);
    for(int i=0;i<=step-1;i++)
        printf("%d %d\n",wayr[i],wayc[i]);
    return 0;
}
样例:
-+--
----
----
-+--
输出:
6
1 1
1 3
1 4
4 1
4 3
4 4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值