1、描述
有一些开始状态的开关,题目让我们操控开关,使得开关从开始状态变成指定状态。注意,当你操作一个开关,其关联的开关也会被操控。例如输入样例一,开始状态为000的三个开关,你要操作使其变成111。那么有以下四种方法:1、只打开开关1,2and3和1关联,所以2and3也变成1。2、只打开开关2。3、只打开开关3。4、打开开关123。
2、问题解决
我们用线性方程组来求解。
由上图表达式,我们可以思考,倘若乘号左边是开关的关联关系,乘号右边是开关操作,那么两个矩阵相乘,结果就是开关变化。由此,我们可以让b为开关变化。意思为当开关从0变为1,那么开关有变化,bi为1;当开关无变化,则bi为0。
例如上面例子,a1=(1,0,1,0)表示,操作开关1,开关3也会改变。即a[i][j]表示操作开关j,开关i也会变化。
所以,我们可以列出矩阵乘法表达式,然后进行高斯消元求解。
3、代码
#include <iostream>
#include<string.h>
#include<math.h>
using namespace std;
const int MAXN=30;
const double EPS=10e-8;
double a[MAXN][MAXN];//存储方程组对应矩阵
bool l[MAXN];//是否为自由元
int start[MAXN]; //开始状态
int endss[MAXN]; //结束状态
//高斯消元模板
inline int solve(const int &n)
{
int res=0,r=0;
for(int i=0; i<n; ++i) l[i]=false;
for(int i=0; i<n; ++i)
{
for(int j=r; j<n; ++j)
{
if(fabs(a[j][i])>EPS)
{
for(int k=i; k<=n; ++k)
swap(a[j][k],a[r][k]);
break;
}
}
if(fabs(a[r][i])<EPS)
{
++res;
continue;
}
for(int j=0; j<n; ++j)
{
if(j!=r&&fabs(a[j][i])>EPS)
{
double tmp=a[j][i]/a[r][i];
for(int k=i; k<=n; ++k)
a[j][k]-=tmp*a[r][k];
}
}
l[i]=true,++r;
}
return res;
}
//模板结束
bool issolve(const int&n){
//判断是否存在无解
for(int i=0; i<n-1; i++)
{
bool flag=true;
for(int j=0;j<n-1;j++){
if(a[i][j]!=0){
flag=false;
continue;
}
}
if(flag&&a[i][n-1]!=0) return false;
}
return true;
}
int main()
{
int k;
cin>>k;
while(k>0)
{
int n;
cin>>n;
memset(a,0,sizeof(a));
memset(start,0,sizeof(start));
memset(endss,0,sizeof(endss));
//输入start
for(int i=0; i<n; i++)
cin>>start[i];
//输入endss
for(int i=0; i<n; i++)
cin>>endss[i];
//输入增广矩阵
int i,j;
while(cin>>i>>j&&i!=0&&j!=0)
a[j-1][i-1]=1;
for(int i=0; i<n; i++){
a[i][n]=start[i]^endss[i];
a[i][i]=1;
}
int ans=solve(n+1);
if(!issolve(n+1)) cout<<"Oh,it's impossible~!!"<<endl;
else cout<<(1<<(ans-1))<<endl;
k--;
}
return 0;
}
注:上文一些图片源于网络,侵权必删