[Gauss]POJ1830 开关问题

中文题 题意不多说

这题乍一看 就是求个自由未知量个数 相当简单

其实呢 其中要注意的细节还是很多的:

1.光求了自由未知量个数 还不够 ∵求的是可行方案的总数  因此 答案是 2^(自由未知量个数)

2.此题转化成方程组比较麻烦

  给了初始状态和最终状态 : ∵对于任意一个开关,最多只能进行一次开关操作。 ∴此开关的初始状态与最终状态不同(即异或)就需进行操作

3.还有一个坑!

  操作第 I 个开关,第J个开关的状态也会变化。

  应将a[J-1][I-1]置1 而非a[I-1][J-1]     (因为是将 可以影响该位置改变的 位置置1

  1 int a[300][300];  // 增广矩阵
  2 int x[300];  // 解
  3 int free_x[300]; // 标记是否为自由未知量
  4
  5 int n;
  6 void debug()
  7 {
  8     for(int i=0;i<n*n;i++)
  9     {
 10         for(int j=0;j<n*n;j++)
 11             printf("%d ", a[i][j]);
 12         printf("\n");
 13     }
 14 }
 15
 16 int Gauss(int n, int m) // n个方程 m个未知数 即 n行m+1列
 17 {
 18     //转换为阶梯形式
 19     int col=0, k, num=0;
 20     for(k=0;k<n && col<m;k++, col++)
 21     {//枚举行
 22         int max_r=k;
 23         for(int i=k+1;i<n;i++)//找到第col列元素绝对值最大的那行与第k行交换
 24             if(abs(a[i][col])>abs(a[max_r][col]))
 25                 max_r=i;
 26         if(max_r!=k)// 与第k行交换
 27             for(int j=col;j<m+1;j++)
 28                 swap(a[k][j], a[max_r][j]);
 29         if(!a[k][col])// 说明该col列第k行以下全是0了
 30         {
 31             k--;
 32             free_x[num++]=col;
 33             continue;
 34         }
 35         for(int i=k+1;i<n;i++)// 枚举要删除的行
 36             if(a[i][col])
 37                 for(int j=col;j<m+1;j++)
 38                     a[i][j]^=a[k][j];
 39     }
 40
 41 //    debug();
 42 //    printf("%d %d\n", col, k);
 43
 44     for(int i=k;i<n;i++)
 45         if(a[i][col])
 46             return -1; // 无解
 47     return m-k;
 48 //    if(k<m)   //m-k为自由未知量个数
 49 //    {
 50 //        int stat=1<<(m-k);
 51 //        int ans=INT_MAX;
 52 //        for(int i=0;i<stat;i++)
 53 //        {
 54 //            int cnt=0;
 55 //            for(int j=0;j<m-k;j++)
 56 //                if(i&(1<<j))
 57 //                {
 58 //                    x[free_x[j]]=1;
 59 //                    cnt++;
 60 //                }
 61 //                else
 62 //                    x[free_x[j]]=0;
 63 //            for(int j=k-1;j>=0;j--)
 64 //            {
 65 //                int tmp;
 66 //                for(tmp=j;tmp<m;tmp++)
 67 //                    if(a[j][tmp])
 68 //                        break;
 69 //                x[tmp]=a[j][m];
 70 //                for(int l=tmp+1;l<m;l++)
 71 //                    if(a[j][l])
 72 //                        x[tmp]^=x[l];
 73 //                cnt+=x[tmp];
 74 //            }
 75 //            if(cnt<ans)
 76 //                ans=cnt;
 77 //        }
 78 //        return ans;
 79 //    }
 80
 81 //    //  唯一解 回代
 82 //    for(int i=m-1;i>=0;i--)
 83 //    {
 84 //        x[i]=a[i][m];
 85 //        for(int j=i+1;j<m;j++)
 86 //            x[i]^=(a[i][j] && x[j]);
 87 //    }
 88 //    int ans=0;
 89 //    for(int i=0;i<n*n;i++)
 90 //        ans+=x[i];
 91 //    return ans;
 92 }
 93
 94
 95 void init()
 96 {
 97     n=4;
 98     memset(a, 0, sizeof(a));
 99     memset(x, 0, sizeof(x));
100     for(int i=0;i<n;i++)
101         for(int j=0;j<n;j++)
102         {
103             int t=i*n+j;
104             a[t][t]=1;
105             if(i>0)
106                 a[(i-1)*n+j][t]=1;
107             if(i<n-1)
108                 a[(i+1)*n+j][t]=1;
109             if(j>0)
110                 a[i*n+j-1][t]=1;
111             if(j<n-1)
112                 a[i*n+j+1][t]=1;
113         }
114 }
115
116 int s1[35], s2[35];
117 int main()
118 {
119     int T;
120     scanf("%d", &T);
121     while(T--)
122     {
123         scanf("%d", &n);
124         for(int i=0;i<n;i++)
125             scanf("%d", &s1[i]);
126         for(int i=0;i<n;i++)
127             scanf("%d", &s2[i]);
128         int X, Y;
129         memset(a, 0, sizeof(a));
130         memset(x, 0, sizeof(x));
131         while(scanf("%d%d", &X, &Y))
132         {
133             if(!X && !Y)
134                 break;
135             a[Y-1][X-1]=1;
136         }
137         for(int i=0;i<n;i++)
138         {
139             a[i][i]=1;
140             a[i][n]=s1[i]^s2[i];
141         }
142         int t=Gauss(n, n);
143         if(t==-1)
144         {
145             printf("Oh,it‘s impossible~!!\n");
146             continue ;
147         }
148         printf("%d\n", 1<<t);
149     }
150     return 0;
151 }

POJ 1830

时间: 2024-08-03 02:00:44

[Gauss]POJ1830 开关问题的相关文章

POJ1830开关问题——gauss消元

题目链接 分析: 第一个高斯消元题目,操作是异或.奇偶能够用0.1来表示,也就表示成bool类型的方程,操作是异或.和加法没有差别 题目中有两个未知量:每一个开关被按下的次数(0.1).每一个开关的转换次数. 题目仅仅和操作次数的奇偶有关,所以用0.1表示之后,对于每一个开关的转换次数就已经知道了.所以仅仅有一个未知量.能够线性表示.练习使用模板 const int maxn = 40; int a[maxn][maxn]; int gauss(int N, int M) { int r, c,

[POJ1830]开关问题(高斯消元,异或方程组)

题目链接:http://poj.org/problem?id=1830 题意:中文题面,求的是方案数. 首先可以知道, 如果方案数不止一个的话,说明矩阵行列式值为0,即存在自由变元,由于变量只有两种状态,那么方案数就是2^自由变元数. 从起始状态到终止状态,只需要关心起始和终止哪些状态不一样就行,也就是翻转奇数次. 由于是倒推,所以开关的影响要反过来存. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long lon

poj1830 开关问题

记 \(a_{i,j}\) 表示第 \(j\) 个开关对第 \(i\) 号开关产生的影响,\(x_i\) 为对第 \(i\) 个开关的操作,则 \[\begin{cases} a_{1,1}x_1\ \mathrm{xor}\ a_{1,2}x_2\ \mathrm{xor}\ \cdots\ \mathrm{xor}\ a_{1,n}x_n=start_1 \ \mathrm{xor}\ end_1 \a_{2,1}x_1\ \mathrm{xor}\ a_{2,2}x_2\ \mathrm{

Poj1830开关问题,高斯消元

高斯消元的入门题. #include<iostream> #include<cstdio> #include<cstring> #include<map> #include<vector> #include<stdlib.h> using namespace std; int Map[100][100]; int gauss(int equ, int var) { int k; int col; for (k = 0, col = 0

poj1830开关问题

[题意] 与poj1222类似,只不过关系不再是通过矩阵体现,而是直接给出. [题解] 根据关系建立出方程组,再高斯消元.若求出变元个数为num,答案即等于2^num.若解方程时有一个方程未知数系数为0,常数不为0,则是无解. [代码] 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 struct node 6 { 7 int vec[31],

高斯消元求解异或方程组

POJ1830 开关问题 对于解异或方程组,系数可以采用二进制压缩,如果系数太多可以使用bitset,但是如果少一点就可以使用下述的写法,更加简单快速 使用bitset的写法更正常的没什么区别,只是对应的消除变为异或操作,另外行变换也会更加简单 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int a[100

【POJ1830】开关问题 高斯消元求自由元

#include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/43482357"); } 题意:中文题. 题解: 呃,求自由元个数,然后输出1<<ans:(自由元就是高斯消元消某个变量x时发现以下所有方程当前此位系数都是0) 如果无解输出那个题中给的串. 诶网上代码真不可看,我绝望了决定照自己

POJ 1830 开关问题

简单的高斯消元取模,答案为2^自由变元的数量,但是题目的意思把I,J搞反了,坑爹... 开关问题 Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 5425   Accepted: 2023 Description 有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开.你的目标是经过若干次

高斯消元法(Gauss Elimination)【超详解&amp;模板】

高斯消元法,是线性代数中的一个算法,可用来求解线性方程组,并可以求出矩阵的秩,以及求出可逆方阵的逆矩阵.高斯消元法的原理是:若用初等行变换将增广矩阵 化为 ,则AX = B与CX = D是同解方程组. 所以我们可以用初等行变换把增广矩阵转换为行阶梯阵,然后回代求出方程的解. 1.线性方程组 1)构造增广矩阵,即系数矩阵A增加上常数向量b(A|b) 2)通过以交换行.某行乘以非负常数和两行相加这三种初等变化将原系统转化为更简单的三角形式(triangular form) 注:这里的初等变化可以通过