hdu 3364 开关灯问题水题。(高斯消元解模线性方程组)
2018-01-28 22:06
239 查看
本人代码模板主要来自“英雄哪里出来”。该博客对于高斯消元的入门讲解十分详尽。
此题可以不用异或方程组来解,可以用模线性方程组来解。
题意:给定灯的数目和开关数目,以及开关控制哪些灯(一个开关可以控制多盏灯)。
之后,给出灯的状态(0:关,1:开) 。问:达到最后灯的状态方法有几种。
大致思路:以对每个开关(S)的操作为变量x(可以理解为取值只有0和1,偶数次操作等于没有操作),
以某盏灯(L)被开关控制的情况为系数,被那个开关控制则对应变量的系数为1,不被那个开关控制
则对应变量系数为0.最后建立模2的线性方程组。
(S1*X1+S2*X2+...+Sn*Xn)%2=L1
(S1'*X1+S2'*X2+...+Sn'*Xn)%2=L2
.
.
.
本题wa点:矩阵在运算过程中是会变的,可以事先开一个二维数组来存储原始矩阵
AC代码如下:
/*模板主要出自英雄从哪里来*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
#define IO ios::sync_with_stdio(false)
#define MAXN 105
typedef long long GG;
#define LL GG
#define ll GG
class GaussMatrix{
public:
int r,c;
LL d[MAXN][MAXN];
LL x[MAXN]; //某个解集
LL xcnt; //解集个数
LL abs(LL v){
return v<0?-v:v;
}
void swap_row(int ra,int rb){//行交换
for(int i=0;i<=c;i++){
LL tmp=d[ra][i];
d[ra][i]=d[rb][i];
d[rb][i]=tmp;
}
}
void swap_col(int ca,int cb){
for(int i=0;i<r;i++){
LL tmp=d[i][ca];
d[i][ca]=d[i][cb];
d[i][cb]=tmp;
}
}
LL gauss(LL mod){
int i,j,k;
int col,maxrow;
for(i=0,col=0;i<r&&col<c;i++) {
maxrow=i;
for(j=i+1;j<r;j++){
if(abs(d[j][col])>abs(d[maxrow][col])){
maxrow=j;
}
}
if(maxrow!=i){
swap_row(i,maxrow);
}
if(d[i][col]==0){
col++;
i--;
continue;
}
for(j=i+1;j<r;j++){
if(d[j][col]){
LL lastcoff = d[i][col];
LL nowcoff = d[j][col];
for(k=col;k<=c;k++){
d[j][k]=(d[j][k]*lastcoff-d[i][k]*nowcoff)%mod;
if(d[j][k]<0) d[j][k] +=mod;
}
}
}
col++;
}
for(j=i;j<r;j++) {
if(d[j][c]){
return -1;
}
}
int free_num=c-i;
for(i=0;i<r&&i<c;i++){
if(!d[i][i]){
for(j=i+1;j<c;j++){
if(d[i][j]) break;
}
if(j<c){
swap_col(i,j);
}
}
}
xcnt=(((LL)1)<<(LL)free_num);
//getAns(mod);
return xcnt;
}
};
ll t,L,S,n,temp,ans,gg;
LL d[MAXN][MAXN];
int main()
{
//ll xx=1125899906842624;
//cout<<xx<<endl;
GaussMatrix a;
IO;
cin>>t;
gg=t;
while(t--)
{
cout<<"Case "<<gg-t<<':'<<endl;
cin>>L>>S;
memset(a.d,0,sizeof(a.d));
memset(d,0,sizeof(d));
a.r=L,a.c=S;
for(int i=1;i<=S;i++){
cin>>n;
for(int j=1;j<=n;j++){
cin>>temp;
d[temp-1][i-1]=a.d[temp-1][i-1]=1;
}
}
cin>>n;
// gg=n;
while(n--){
for(int i=0;i<L;i++){
cin>>temp;
a.d[i][S]=temp;
}
ans=a.gauss(2);
if(ans==-1) cout<<0<<endl;
else
cout<<ans<<endl;
//if(n)
for(int i=0;i<L;i++){//wa点
for(int j=0;j<S;j++){
a.d[i][j]=d[i][j];
}
}
}
}
return 0;
}
此题可以不用异或方程组来解,可以用模线性方程组来解。
题意:给定灯的数目和开关数目,以及开关控制哪些灯(一个开关可以控制多盏灯)。
之后,给出灯的状态(0:关,1:开) 。问:达到最后灯的状态方法有几种。
大致思路:以对每个开关(S)的操作为变量x(可以理解为取值只有0和1,偶数次操作等于没有操作),
以某盏灯(L)被开关控制的情况为系数,被那个开关控制则对应变量的系数为1,不被那个开关控制
则对应变量系数为0.最后建立模2的线性方程组。
(S1*X1+S2*X2+...+Sn*Xn)%2=L1
(S1'*X1+S2'*X2+...+Sn'*Xn)%2=L2
.
.
.
本题wa点:矩阵在运算过程中是会变的,可以事先开一个二维数组来存储原始矩阵
AC代码如下:
/*模板主要出自英雄从哪里来*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
#define IO ios::sync_with_stdio(false)
#define MAXN 105
typedef long long GG;
#define LL GG
#define ll GG
class GaussMatrix{
public:
int r,c;
LL d[MAXN][MAXN];
LL x[MAXN]; //某个解集
LL xcnt; //解集个数
LL abs(LL v){
return v<0?-v:v;
}
void swap_row(int ra,int rb){//行交换
for(int i=0;i<=c;i++){
LL tmp=d[ra][i];
d[ra][i]=d[rb][i];
d[rb][i]=tmp;
}
}
void swap_col(int ca,int cb){
for(int i=0;i<r;i++){
LL tmp=d[i][ca];
d[i][ca]=d[i][cb];
d[i][cb]=tmp;
}
}
LL gauss(LL mod){
int i,j,k;
int col,maxrow;
for(i=0,col=0;i<r&&col<c;i++) {
maxrow=i;
for(j=i+1;j<r;j++){
if(abs(d[j][col])>abs(d[maxrow][col])){
maxrow=j;
}
}
if(maxrow!=i){
swap_row(i,maxrow);
}
if(d[i][col]==0){
col++;
i--;
continue;
}
for(j=i+1;j<r;j++){
if(d[j][col]){
LL lastcoff = d[i][col];
LL nowcoff = d[j][col];
for(k=col;k<=c;k++){
d[j][k]=(d[j][k]*lastcoff-d[i][k]*nowcoff)%mod;
if(d[j][k]<0) d[j][k] +=mod;
}
}
}
col++;
}
for(j=i;j<r;j++) {
if(d[j][c]){
return -1;
}
}
int free_num=c-i;
for(i=0;i<r&&i<c;i++){
if(!d[i][i]){
for(j=i+1;j<c;j++){
if(d[i][j]) break;
}
if(j<c){
swap_col(i,j);
}
}
}
xcnt=(((LL)1)<<(LL)free_num);
//getAns(mod);
return xcnt;
}
};
ll t,L,S,n,temp,ans,gg;
LL d[MAXN][MAXN];
int main()
{
//ll xx=1125899906842624;
//cout<<xx<<endl;
GaussMatrix a;
IO;
cin>>t;
gg=t;
while(t--)
{
cout<<"Case "<<gg-t<<':'<<endl;
cin>>L>>S;
memset(a.d,0,sizeof(a.d));
memset(d,0,sizeof(d));
a.r=L,a.c=S;
for(int i=1;i<=S;i++){
cin>>n;
for(int j=1;j<=n;j++){
cin>>temp;
d[temp-1][i-1]=a.d[temp-1][i-1]=1;
}
}
cin>>n;
// gg=n;
while(n--){
for(int i=0;i<L;i++){
cin>>temp;
a.d[i][S]=temp;
}
ans=a.gauss(2);
if(ans==-1) cout<<0<<endl;
else
cout<<ans<<endl;
//if(n)
for(int i=0;i<L;i++){//wa点
for(int j=0;j<S;j++){
a.d[i][j]=d[i][j];
}
}
}
}
return 0;
}
相关文章推荐
- HDU 3364 Lanterns (高斯消元解开关问题)
- HDU 3364 Lanterns(高斯消元入门题目——开关问题)
- HDOJ 题目3364 Lanterns(高斯消元,开关灯问题)
- HDOJ 题目3364 Lanterns(高斯消元,开关灯问题)
- hdu 5755 Gambler Bo 高斯消元 + 取余逆元 模3系下的开关灯问题
- 经典问题:开关灯问题(高斯消元)(3364)
- hdu 5755 Gambler Bo 三进制高斯消元(开关问题变形)
- poj 1830 开关问题(线性方程组,高斯消元)
- POJ - 1830 - 开关问题 ,POJ - 3185 - The Water Bowls,POJ - 1753 -Flip Game - (高斯消元解异或方程组)
- poj1830--开关问题(高斯消元问题1)
- [poj 1830]开关问题 高斯消元+自由变量枚举
- POJ 1222 & 1681 & 1830 & 3185 开关灯问题 (高斯消元 & 异或方程组)
- poj 1830 开关问题 高斯消元
- POJ 1830 开关问题 (高斯消元)
- poj 1830 开关问题 高斯消元
- hdu 3949 Xor (高斯消元解决xor问题)
- HDU 2181 哈密顿绕行世界问题( 搜索水题bfs+dfs)
- poj1830 高斯消元开关问题
- poj 1830 开关问题 (高斯消元 )
- POJ 1830 开关问题 高斯消元求自由变元