poj 一类开关问题

博客介绍了如何利用高斯消元法解决一类开关问题,特别是在面对大量数据时,这种方法能提高效率。讨论了POJ 1222题目,并提供了状态压缩枚举与高斯消元的模板,重点在于递推策略。
摘要由CSDN通过智能技术生成

        这是一类开关问题,对于这类问题可以状态压缩枚举搞,也可以用高斯消元,当数据量比较大的时候高斯消元效率更高。

poj 1222 

         状态压缩枚举第一行所有的翻转情况,从第二行开始依次递推即可。

         

#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
int dx[5]={0,0,1,-1,0};
int dy[5]={-1,1,0,0,0};

int n,m;
int tile[10][10];
int out[10][10];
int flip[10][10];


int get(int x,int y)
{
   int c=tile[x][y];
   for(int i=0;i<5;i++)
   {
      int tx=x+dx[i],ty=y+dy[i];
      if(1<=tx && tx<=n && 1<=ty && ty<=m)
        c+=flip[tx][ty];
   }
   return c%2;
}

int cal()
{
  for(int i=2;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
       if(get(i-1,j)!=0)
            flip[i][j]=1;
    }
  for(int i=1;i<=m;i++)
    if(get(n,i)!=0)return -1;

  int res=0;
  for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
        res+=flip[i][j];
  return res;
}

void solve()
{
  int res=-1;
  for(int i=0;i<(1<<m);i++)
  {
     memset(flip,0,sizeof(flip));
     for(int j=1;j<=m;j++)
     {
       flip[1][m-j+1]=(i>>(j-1))&1;
     }
     int num=cal();
     if(num>=0 && (res<0 || res>num))
     {
       res=num;
       for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
         out[i][j]=flip[i][j];
     }
  }
}

int main()
{
   int T,test=0;
   cin>>T;
   while(T--)
   {
     n=5,m=6;
     for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
          cin>>tile[i][j];
        }
     solve();
     printf("PUZZLE #%d\n",++test);
     for(int i=1;i<=n;i++)
     {
       for(int j=1;j<=m;j++)
       {
          if(j==1)printf("%d",out[i][j]);
          else printf(" %d",out[i][j]);
       }
       printf("\n");
     }
   }
   return 0;
}
也可以高斯消元求解:

模板

#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn=50;
int equ,var; //equ 个方程,var个未知数,增广矩阵 equ行 var+1列
int a[maxn][maxn]; //系数矩阵
int x[maxn]; //解集
int free_x[maxn]; //存储自由变元
int free_num; //  自由变元的个数

void Debug(void)
{
    int i, j;
    for (i = 0; i < equ; i++)
    {
        for (j = 0; j < var + 1; j++)
        {
            cout << a[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}

int Gauss()
{
   int max_r,col,k;  // 在当前col列中找到一个最大值 用max_r存储这一行
   free_num=0;
   for(k=0,col=0;k<equ&&col<var;k++,col++)  //枚举行 化行阶梯
   {
       max_r=k;
       for(int i=k+1;i<equ;i++)
       {
          if(abs(a[i][col])>abs(a[max_r][col])) //减小误差
          {
              max_r=i;
          }
       }
       if(a[max_r][col]==0) //说明该列所对应的x是自由元变量
       {
          k--;
          free_x[free_num++]=col;
          continue;
       }
       if(max_r!=k) //交换两行
       {
          for(int j=col;j<var+1;j++)
            swap(a[k][j],a[max_r][j]);
       }
       for(int i=k+1;i<equ;i++)
       {
          if(a[i][col]!=0)
          {
             for(int j=col;j<var+1;j++)
                a[i][j]=a[i][j]^a[k][j];
          }
       }
   }
   for(int i=k;i<equ;i++)
   {
      if(a[i][col]!=0)return -1;
   }
   if(k<var)return var-k;

   for(int i=var-1;i>=0;i--)
   {
      x[i]=a[i][var];
      for(int j=i+1;j<var;j++)
      x[i]=x[i]^(a[i][j] && x[j]);
   }
   return 0;
}

int main()
{
   int n,test=0;
   scanf("%d",&n);
   while(n--)
   {
      equ=30,var=30;
      memset(a,0,sizeof(a));
      memset(x,0,sizeof(x));

      for(int i=0;i<5;i++)
        for(int j=0;j<6;j++)
        {
          int t;
          scanf("%d",&t);
          a[i*6+j][var]=t;
          a[i*6+j][i*6+j]=1;
          if(i-1>=0)a[(i-1)*6+j][i*6+j]=1;
          if(i+1<5)a[(i+1)*6+j][i*6+j]=1;
          if(j-1>=0)a[i*6+j-1][i*6+j]=1;
          if(j+1<6)a[i*6+j+1][i*6+j]=1;
        }
      Gauss();
       //Debug();

       printf("PUZZLE #%d\n",++test);
       for(int i=0;i<5;i++)
        {
         for(int j=0;j<6;j++)
         {
          if(j==0)printf("%d",x[i*6+j]);
          else printf(" %d",x[i*6+j]);
         }
         printf("\n");
        }
   }
   return 0;
}



poj 1681 http://poj.org/problem?id=1681

枚举自由元变量

#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn=400;
const int INF=99999999;

char s[40][40];
int equ,var;
int a[maxn][maxn],n;
int x[maxn];
int free_x[maxn];
int free_num;


void Debug(void)
{
    int i, j;
    for (i = 0; i < equ; i++)
    {
        for (j = 0; j < var + 1; j++)
        {
            cout << a[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}

int Gauss()
{
   int max_r,col,k;  // 在当前col列中找到一个最大值 用max_r存储这一行
   free_num=0;
   for(k=0,col=0;k<equ&&col<var;k++,col++)  //枚举行 化行阶梯
   {
       max_r=k;
       for(int i=k+1;i<equ;i++)
       {
          if(abs(a[i][col])>abs(a[max_r][col])) //减小误差
          {
              max_r=i;
          }
       }
       if(a[max_r][col]==0) //说明该列所对应的x是自由元变量
       {
          k--;
          free_x[free_num++]=col;
          continue;
       }
       if(max_r!=k) //交换两行
       {
          for(int j=col;j<var+1;j++)
            swap(a[k][j],a[max_r][j]);
       }
       for(int i=k+1;i<equ;i++)
       {
          if(a[i][col]!=0)
          {
             for(int j=col;j<var+1;j++)
                a[i][j]=a[i][j]^a[k][j];
          }
       }
   }
   for(int i=k;i<equ;i++)
   {
      if(a[i][col]!=0)return -1;
   }
   if(k<var)return var-k;

   for(int i=var-1;i>=0;i--)
   {
      x[i]=a[i][var];
      for(int j=i+1;j<var;j++)
      x[i]=x[i]^(a[i][j] && x[j]);
   }
   return 0;
}

void init()
{
    memset(a,0,sizeof(a));
    memset(x,0,sizeof(x));
    for(int i=0;i<4;i++)
      for(int j=0;j<4;j++)
        {
            a[i*4+j][i*4+j]=1;
            if(i-1>=0)a[(i-1)*4+j][i*4+j]=1;
            if(i+1<4)a[(i+1)*4+j][i*4+j]=1;
            if(j-1>=0)a[i*4+j-1][i*4+j]=1;
            if(j+1<4)a[i*4+j+1][i*4+j]=1;
        }
}

int solve()
{
     int num=Gauss();
      if(num==-1)
      {
        return INF;
      }
      else if(num==0)
      {
         int cnt=0;
         for(int i=0;i<n*n;i++)cnt+=x[i];
         return cnt;
      }
      else  //枚举自由元的
      {
          int tot=(1<<free_num),cnt=0,ans=99999999;
          for(int i=0;i<tot;i++)
          {
             cnt=0;
             for(int j=0;j<free_num;j++)
             {
                 if( i&(1<<j) )
                 {
                     x[free_x[j]]=1;
                     cnt++;
                 }
                 else
                     x[free_x[j]]=0;
             }

             for(int j=var-free_num-1;j>=0;j--)
             {
                 int idx;
                 for(idx=j;idx<var;idx++)
                 {
                     if(a[j][idx])break;
                 }

                 x[j]=a[j][var];

                 for(int l=idx+1;l<var;l++)
                 {
                    if(a[j][l])
                        x[j]=x[j]^x[l];
                 }
                 cnt+=x[j];
             }
             ans=min(ans,cnt);
          }
         return ans;
      }
}

int main()
{
  for(int i=0;i<4;i++)scanf("%s",s[i]);
  n=4;
  equ=16,var=16;
  init();
  for(int i=0;i<4;i++)
    for(int j=0;j<4;j++)
    {
       if( s[i][j]=='w' )a[i*4+j][16]=1;
       else a[i*4+j][16]=0;
    }
  int a1=solve();

  init();
  for(int i=0;i<4;i++)
    for(int j=0;j<4;j++)
    {
       if( s[i][j]=='w' )a[i*4+j][16]=0;
       else a[i*4+j][16]=1;
    }
  int a2=solve();

  if(a1==INF && a2==INF)
      printf("Impossible\n");
  else
      printf("%d\n",min(a1,a2));

  return 0;
}

poj 3185

#include <iostream>
#include <stdio.h>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;

const int maxn=50;

int equ,var; //equ 个方程,var个未知数,增广矩阵 equ行 var+1列
int a[maxn][maxn]; //系数矩阵
int x[maxn]; //解集
int free_x[maxn]; //存储自由变元
int free_num; //  自由变元的个数

int s[40];
void Debug(void)
{
    int i, j;
    for (i = 0; i < equ; i++)
    {
        for (j = 0; j < var + 1; j++)
        {
            cout << a[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}

int Gauss()
{
   int max_r,col,k;  // 在当前col列中找到一个最大值 用max_r存储这一行
   free_num=0;
   for(k=0,col=0;k<equ&&col<var;k++,col++)  //枚举行 化行阶梯
   {
       max_r=k;
       for(int i=k+1;i<equ;i++)
       {
          if(abs(a[i][col])>abs(a[max_r][col])) //减小误差
          {
              max_r=i;
          }
       }
       if(a[max_r][col]==0) //说明该列所对应的x是自由元变量
       {
          k--;
          free_x[free_num++]=col;
          continue;
       }
       if(max_r!=k) //交换两行
       {
          for(int j=col;j<var+1;j++)
            swap(a[k][j],a[max_r][j]);
       }
       for(int i=k+1;i<equ;i++)
       {
          if(a[i][col]!=0)
          {
             for(int j=col;j<var+1;j++)
                a[i][j]=a[i][j]^a[k][j];
          }
       }
   }
   for(int i=k;i<equ;i++)
   {
      if(a[i][col]!=0)return -1;
   }
   if(k<var)return var-k;

   for(int i=var-1;i>=0;i--)
   {
      x[i]=a[i][var];
      for(int j=i+1;j<var;j++)
      x[i]=x[i]^(a[i][j] && x[j]);
   }
   return 0;
}

void init()
{
   memset(a,0,sizeof(a));
   memset(x,0,sizeof(x));
   for(int i=0;i<20;i++)
   {
       a[i][i]=1;
       if(i-1>=0)a[i-1][i]=1;
       if(i+1<20)a[i+1][i]=1;
       if(s[i])a[i][20]=1;
       else a[i][20]=0;
   }
}
int solve()
{
     int num=Gauss();
      if(num==-1)
      {
        return -1;
      }
      else if(num==0)
      {
         int cnt=0;
         for(int i=0;i<20;i++)cnt+=x[i];
         return cnt;
      }
      else  //枚举自由元的
      {
          int tot=(1<<free_num),cnt=0,ans=99999999;
          for(int i=0;i<tot;i++)
          {
             cnt=0;
             for(int j=0;j<free_num;j++)
             {
                 if( i&(1<<j) )
                 {
                     x[free_x[j]]=1;
                     cnt++;
                 }
                 else
                     x[free_x[j]]=0;
             }

             for(int j=var-free_num-1;j>=0;j--)
             {
                 int idx;
                 for(idx=j;idx<var;idx++)
                 {
                     if(a[j][idx])break;
                 }

                 x[j]=a[j][var];

                 for(int l=idx+1;l<var;l++)
                 {
                    if(a[j][l])
                        x[j]=x[j]^x[l];
                 }
                 cnt+=x[j];
             }
             ans=min(ans,cnt);
          }
         return ans;
      }
}

int main()
{
   equ=20,var=20;
   for(int i=0;i<20;i++)scanf("%d",&s[i]);
   init();
   int num=solve();
   printf("%d\n",num);
   return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值