zoukankan      html  css  js  c++  java
  • poj 3279 Fliptile(关灯问题)

    题意:给一个n*m的矩阵,0表示灯关,1表示开,按下(x,y),那么与他相连和本身的共5个灯翻转,输出翻转次数最少的 字典序最小的方案

    分析:非常经典的题,一个灯按两次,相当于没按,那么只要求哪些灯按,哪些灯没按,直接枚举状态有2^(n*m)),太大,接下来我们考虑如何让一个灯翻转,显然相连的四个灯和本身,那么我枚举了第一排的灯是否按,最多只有2^15,那么如果第0行有灯没关,那么第一行相应的就要按,如果关了,下面的就不能按,也就是说,第一行确定了之后,接下来的所有行都确定了,模拟搞就行了,f(i,j)表示被翻转的状态,g表示初始状态,字典序,只要res=ans的时候,比较一下就行了

    还有高斯消元法,还没搞

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn=17;
    const int dx[]={0,0,0,1,-1};
    const int dy[]={1,-1,0,0,0};
    int g[maxn][maxn],f[maxn][maxn],t[maxn][maxn],a[maxn][maxn];
    int m,n;
    
    void siv(int x,int y){
        for(int i=0;i<5;i++){
            int nx=x+dx[i];
            int ny=y+dy[i];
            if(nx<0||nx>=n||ny<0||ny>=m)
              continue;
            f[nx][ny]^=1;
        }
    }
    
    bool cmp(){
        for(int i=0;i<n;i++)
          for(int j=0;j<m;j++)
            if(a[i][j]>t[i][j])
              return true;
            else if(a[i][j]<t[i][j])
              return false;
        return false;
    }
    
    int main(){
        while(~scanf("%d%d",&n,&m)){
            for(int i=0;i<n;i++)
                for(int j=0;j<m;j++)
                  scanf("%d",&g[i][j]);
            int tmp=(1<<m),ans=15*15;
            for(int i=0;i<tmp;i++){
                int res=0;
                memset(f,0,sizeof(f));
                memset(t,0,sizeof(t));
                for(int k=0;k<m;k++)
                  if(i&(1<<k)){
                    siv(0,k);
                    t[0][k]=1;
                    res++;
                  }
                for(int k=1;k<n;k++)
                  for(int j=0;j<m;j++)
                    if((f[k-1][j]+g[k-1][j])%2==1){
                      siv(k,j);
                      t[k][j]=1;
                      res++;
                    }
                for(int j=0;j<m;j++)
                  if((f[n-1][j]+g[n-1][j])%2!=0)
                    res=15*15;
                if(res<ans||(res==ans&&cmp())){
                    for(int k=0;k<n;k++)
                      for(int j=0;j<m;j++)
                        a[k][j]=t[k][j];
                    ans=res;
                }
            }
            if(ans==15*15){
                puts("IMPOSSIBLE");
                continue;
            }
            for(int i=0;i<n;i++){
                printf("%d",a[i][0]);
                for(int j=1;j<m;j++)
                  printf(" %d",a[i][j]);
                puts("");
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Azure 虚拟机安全加固整理
    AzureARM 使用 powershell 扩容系统磁盘大小
    Azure Linux 云主机使用Root超级用户登录
    Open edX 配置 O365 SMTP
    powershell 根据错误GUID查寻错误详情
    azure 创建redhat镜像帮助
    Azure Powershell blob中指定的vhd创建虚拟机
    Azure Powershell 获取可用镜像 PublisherName,Offer,Skus,Version
    Power BI 连接到 Azure 账单,自动生成报表,可刷新
    Azure powershell 获取 vmSize 可用列表的命令
  • 原文地址:https://www.cnblogs.com/jihe/p/5571984.html
Copyright © 2011-2022 走看看