POJ 2965 The Pilots Brothers' refrigerator

题意:给一个4×4的矩阵,“+”表示该位置是锁这的,“-”表示该位置开着的,当改变某个位置的状态时,相应同行和同列的状态也改变,求最少的操作次数使全部16个位置开着,即所有位置是“-”状态。


解题思路:首先想到的是暴力:16个位置,每个位置有改变和不改变2种状态,共有2^16=65536种状态,用2进制或16层循环即可,然后看每种情况是否符合条件,最后找出操作次数最少的就行,中间的路径用数组保存下来。可惜啊,TLE...


还好,暴力能看出每种情况的路径,而且,暴力的结果绝对是对的!OK,根据暴力的结果找规律。


              


根据暴力的路径可以看出对于每个“+”只要把这个“+”所在行和列的所有点转换一下就行,有第三个样例可以看出,只要把重复的去掉就行!(因为转变2次相当于每操作,所以舍去),接下来就简单了,枚举每个“+”即可。


Memory: 344K		Time: 63MS

#include <stdio.h>
#include <string.h>

using namespace std;
int b[6][6];//标记状态
void turn(int x,int y)//转换(x,y)点状态
{
    for(int i=1;i<=4;i++)
    {
        if(b[x][i]==0) b[x][i]=1;
        else b[x][i]=0;
        if(b[i][y]==0) b[i][y]=1;
        else b[i][y]=0;
    }
    if(b[x][y]==0) b[x][y]=1;
    else b[x][y]=0;
}

int main()
{
    char s[5][6];
//    freopen("in.txt","r",stdin);
    while(scanf("%s%s%s%s",s[1],s[2],s[3],s[4])!=EOF)
    {
        memset(b,0,sizeof(b));
        for(int i=1;i<=4;i++)
        {
            for(int j=0;j<4;j++)
            {
                if(s[i][j]=='+')
                {
                    turn(i,j+1);
                }
            }
        }
        int sum=0;//统计最后是"1"状态点
        for(int i=1;i<=4;i++)
            for(int j=1;j<=4;j++)
            {
                if(b[i][j]==1) sum++;
            }
        printf("%d\n",sum);
        for(int i=1;i<=4;i++)//打印路径
            for(int j=1;j<=4;j++)
            {
                if(b[i][j]==1)
                {
                    printf("%d %d\n",i,j);
                }
            }
    }
    return 0;
}

附上暴力代码。。。

#include <iostream>
#include <stdio.h>
#include <string.h>

using namespace std;

struct NODE
{
    int x,y,nm;
}n[100][20];
int t[6][6];
void turn(int x,int y)
{
    for(int i=1;i<=4;i++)
    {
        t[x][i]=-t[x][i];
        t[i][y]=-t[i][y];
    }
    t[x][y]=-t[x][y];
}

int main()
{
    char s[5][5];
    int a[6][6],b[6][6];
//    freopen("in.txt","r",stdin);
    while(scanf("%s%s%s%s",s[1],s[2],s[3],s[4])!=EOF)
    {
        for(int i=1;i<=4;i++)
            for(int j=0;j<4;j++)
            {
                if(s[i][j]=='+') a[i][j+1]=-1;
                else a[i][j+1]=1;
            }
        memset(b,0,sizeof(b));
        int ans=100000,k=1;
        for(b[1][1]=0;b[1][1]<=1;b[1][1]++)//16层循环啊.....
        for(b[1][2]=0;b[1][2]<=1;b[1][2]++)
        for(b[1][3]=0;b[1][3]<=1;b[1][3]++)
        for(b[1][4]=0;b[1][4]<=1;b[1][4]++)
        for(b[2][1]=0;b[2][1]<=1;b[2][1]++)
        for(b[2][2]=0;b[2][2]<=1;b[2][2]++)
        for(b[2][3]=0;b[2][3]<=1;b[2][3]++)
        for(b[2][4]=0;b[2][4]<=1;b[2][4]++)
        for(b[3][1]=0;b[3][1]<=1;b[3][1]++)
        for(b[3][2]=0;b[3][2]<=1;b[3][2]++)
        for(b[3][3]=0;b[3][3]<=1;b[3][3]++)
        for(b[3][4]=0;b[3][4]<=1;b[3][4]++)
        for(b[4][1]=0;b[4][1]<=1;b[4][1]++)
        for(b[4][2]=0;b[4][2]<=1;b[4][2]++)
        for(b[4][3]=0;b[4][3]<=1;b[4][3]++)
        for(b[4][4]=0;b[4][4]<=1;b[4][4]++)
        {
            int kk=1;
            for(int i=1;i<=4;i++)
                for(int j=1;j<=4;j++)
                    t[i][j]=a[i][j];
            for(int i=1;i<=4;i++)
            {
                for(int j=1;j<=4;j++)
                {
                    if(b[i][j]==1)
                    {
                        turn(i,j);
                        n[k][kk].x=i;
                        n[k][kk].y=j;
                        kk++;
                    }
                }
            }
            kk--;
            n[k][1].nm=kk;
            int ok=1;
            for(int i=1;i<=4;i++)
            {
                for(int j=1;j<=4;j++)
                {
                    if(t[i][j]==-1){ok=0;break;}
                }
            }
            if(ok)
            {
                ans=min(ans,kk);
                k++;
            }
        }
        printf("%d\n",ans);
        for(int i=1;i<k;i++)
        {
            int m=n[i][1].nm;
            if(m==ans)
            {
                for(int j=1;j<=m;j++)
                {
                    printf("%d %d\n",n[i][j].x,n[i][j].y);
                }
                break;
            }
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值