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
  • 相关阅读:
    MS CRM 2011 RC中的新特性(4)——活动方面之批量编辑、自定义活动
    最近的一些有关MS CRM 2011的更新
    MS CRM 2011 RC中的新特性(6)——连接
    MS CRM 2011 RC中的新特性(7)—仪表板
    参加MS CRM2011深度培训课程——第一天
    MS CRM 2011插件调试工具
    MS CRM2011实体介绍(四)——目标管理方面的实体
    MS CRM 2011 RC中的新特性(3)——客户服务管理方面
    MS CRM 2011 RC中的新特性(8)—数据管理
    ExtAspNet 登陆
  • 原文地址:https://www.cnblogs.com/jihe/p/5571984.html
Copyright © 2011-2022 走看看