• 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

    Sample Output

    0 0 0 0
    1 0 0 1
    1 0 0 1
    0 0 0 0

    解题思路:

      首先需要明确每个格子只有两种情况,就是要么翻和要么不翻,因为翻奇数次都与翻1次,而翻偶数次等于没翻。再来看一下数据范围n和m最大都为15,范围不是很大,但是全部枚举的话应该也会超时,所以我们要找到一个方案减少枚举量,我们发现如果一行的状态已经确定了,那么它接下来的是不是都确定了。下一行都要保证上一行全为0就可以了,最后只需要判断一下最后一行是否都为0就可以了,而第一行有n个棋子,它的状态也就是有2^n种。我们可以用一个含有16位的二进制数来表示它的状态,如果第i位为1表示该格子需要翻转,如果为0,则表示不翻转,翻转完第一行,仅接着翻第2行,每行的状态由其上一行的状态所确定。这样只要判断最后一行是否可以全部为0即可,如果为0,判断是否比答案更小,如果更小,则对答案进行更新。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<string>
    #include<set>
    #include<cmath>
    #include<list>
    #include<deque>
    #include<cstdlib>
    #include<bitset>
    #include<stack>
    #include<map>
    #include<queue>
    using namespace std;
    typedef long long ll;
    const int INF=0x3f3f3f3f;
    const double PI=acos(-1.0);
    const double eps=1e-6;
    const ll mod=1e9+7;
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    int n,m,mp[20][20],tmp[20][20],cnt[20][20],ans[20][20],res;
    void flip(int x,int y)  //翻转,用异或符操作
    {
        tmp[x][y]^=1;
        tmp[x+1][y]^=1;
        tmp[x-1][y]^=1;
        tmp[x][y+1]^=1;
        tmp[x][y-1]^=1;
    }
    int main()
    {
        ios_base::sync_with_stdio(false); cin.tie(0);
        cin>>m>>n;
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
            {
                cin>>mp[i][j];
            }
        }
        res=INF;  //初始答案为无穷大
        for(int s=0;s<(1<<n);s++)  //枚举第一行的所有状态
        {
            int tot=0;
            memset(cnt,0,sizeof(cnt));
            for(int i=1;i<=m;i++)
            {
                for(int j=1;j<=n;j++)
                {
                    tmp[i][j]=mp[i][j];
                }
            }
            for(int i=0;i<n;i++)
            {
                if(((s>>i)&1))  //如果第i+1位为1,则对其进行翻转
                {
                    tot++;
                    cnt[1][i+1]=1;
                    flip(1,i+1);
                }
            }
            for(int i=2;i<=m;i++)  //翻转第2至m行
            {
                for(int j=1;j<=n;j++)
                {
                    if(tmp[i-1][j])
                    {
                        tot++;
                        cnt[i][j]=1;
                        flip(i,j);
                    }
                }
            }
            int flag=1;
            for(int i=1;i<=n;i++)  //判断是否合法
            {
                if(tmp[m][i]!=0)
                {
                    flag=0;
                    break;
                }
            }
            if(flag&&tot<res)  //合法且比当前答案小对答案进行更新
            {
                res=tot;
                for(int i=1;i<=m;i++)
                {
                    for(int j=1;j<=n;j++)
                    {
                        ans[i][j]=cnt[i][j];
                    }
                }
            }
        }
        if(res==INF)  //不能实现
        {
            cout<<"IMPOSSIBLE"<<endl;
            return 0;
        }
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(j==1) cout<<ans[i][j];
                else cout<<" "<<ans[i][j];
            }
            cout<<endl;
        }
        return 0;
    }

    题目链接:http://poj.org/problem?id=1753

    题目大意:

      给你一个4*4的棋盘,上面摆了16个棋子,每个棋子有两面,一面是黑色一面是白色,给出棋盘的初始状态,每次可以翻一个棋子,而且每次翻的时候连着四周的棋子一起翻,问最少几次操作可以使棋盘全变为白棋或者黑棋。

    思路:

      首先可以用DFS做,数据范围较小,最多翻16个棋子(每个棋子要么翻要么不翻,再翻就和原来一样了),枚举翻的棋子数,然后用DFS搜索翻该棋子数的所有情况,然后进行判断是否全为黑或全为白,就可以找出答案。

      当然也可以用二进制枚举的方法,总共16个棋子,对应2^16种状态,直接暴力枚举全部枚举全部情况,保留答案的最小值,与上面那题类似。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<string>
    #include<set>
    #include<cmath>
    #include<list>
    #include<deque>
    #include<cstdlib>
    #include<bitset>
    #include<stack>
    #include<map>
    #include<queue>
    using namespace std;
    typedef long long ll;
    const int INF=0x3f3f3f3f;
    const double PI=acos(-1.0);
    const double eps=1e-6;
    const ll mod=1e9+7;
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    int mp[5][5],tmp[5][5],ans;
    void flip(int x,int y)  //翻转
    {
        tmp[x][y]^=1;
        tmp[x+1][y]^=1;
        tmp[x-1][y]^=1;
        tmp[x][y+1]^=1;
        tmp[x][y-1]^=1;
    }
    int main()
    {
        ios_base::sync_with_stdio(false); cin.tie(0);
        for(int i=1;i<=4;i++)
        {
            for(int j=1;j<=4;j++)
            {
                char c;
                cin>>c;
                if(c=='w') mp[i][j]=0;
                else mp[i][j]=1;
            }
        }
        ans=17;
        for(int s=0;s<(1<<16);s++)  //枚举所有情况
        {
            int tot=0;
            for(int i=1;i<=4;i++)
            {
                for(int j=1;j<=4;j++)
                    tmp[i][j]=mp[i][j];
            }
            for(int i=0;i<16;i++)
            {
                if((s>>i)&1)
                {
                    int x=(i+1)/4+1;  //判断第i+1棋子的坐标,然后对其翻转
                    int y=(i+1)%4;
                    if(y==0){x--;y=4;}
                    tot++;
                    flip(x,y);
                }
            }
            int flag=1;
            for(int i=1;i<=4;i++)  //判断是否合法
            {
                for(int j=1;j<=4;j++)
                {
                    if(tmp[i][j]!=tmp[1][1])
                    {
                        flag=0;
                        break;
                    }
                }
                if(flag==0) break;
            }
            if(flag&&tot<ans)  //合法更新答案
                ans=tot;
        }
        if(ans==17)
            cout<<"Impossible"<<endl;
        else
            cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    hdu 1181 (搜索BFS,深搜DFS,并查集)
    [置顶] ZSTACK之OSAL_Nv非易失性存储解读上
    Android中利用Fragment显示为两屏
    WCF也可以做聊天程序
    Myeclipse 连接MSSqlServer
    Mysql和Oracle的卸载
    第 5堂作业
    hdu 3421 Max Sum II
    【求助】一个菜鸟java作业,帮忙看一下错在哪儿,题目是判断回文数
    netcat使用
  • 原文地址:https://www.cnblogs.com/zjl192628928/p/10031802.html
Copyright © 2020-2023  润新知