poj1830

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;
}

 

注:上文一些图片源于网络,侵权必删

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值