poj 1830 开关问题
1、描述
有一些开始状态的开关,题目让我们操控开关,使得开关从开始状态变成指定状态。
注意,当你操作一个开关,其关联的开关也会被操控。例如输入样例一,开始状态为的三个开关,你要操作使其变成。那么有以下四种方法:
- 只打开开关, 和关联,所以 也变成
- 只打开开关,
- 只打开开关,
- 打开开关
初始状态
终止状态
按下号开关,会影响号开关:
我能影响谁
->(1,0,1,0)->{,}
->(0,1,0,0)->{}
->{}
->{}
谁能影响我
操作每个开关后,影响的情况
2、问题解决
我们用线性方程组来求解。
由上图表达式,我们可以思考,倘若乘号左边是开关的关联关系,乘号右边是开关操作,那么两个矩阵相乘,结果就是开关变化。由此,我们可以让为开关变化。
意思为当开关从变为,那么开关有变化,为;当开关无变化,则为。
例如上面例子,表示,操作开关,开关也会改变。即表示操作开关,开关也会变化。
所以,我们可以列出矩阵乘法表达式,然后进行高斯消元求解。
:为什么这里有反着记录的呢?
答:我们希望以方程组的形式对原问题进行求解。那么,由于有$n n$个方程。
我们以第盏灯为例,我们知道它的初始状态和终止状态,我们就可以研究它是在初始状态下,通过什么样的操作变化到终止状态的。因为灯开关的特殊性,关联一次就变化一次,所以,我们还可以取一巧:看看开始状态和终止状态是一样的呢,还是有了变化。
-
一样的
中间的变化是偶数次。用异或运算来描述就是异或和等于。 -
不一样
中间的变化是奇数次。用异或运算来描述就是异或和等。
总结:我们关心的是状态的变化情况
号灯的变化,受和它相关联灯的制约,以上面的图为例说明:
第盏灯的变化,受三个灯的影响,我们可以把盏灯的变化情况看作
描述的说是:
- 号灯操作,影响号灯的状态
- 号灯操作,不影响号灯的状态
- 号灯操作,影响号灯的状态
- 号灯操作,影响号灯的状态
当然,只是说影响,但每个灯还有是权力决定自己是不是要操作的。
这就引出了一个系数的问题:
“我是一号灯,谁能影响我的状态?”
这玩意和题目中给的“我是号灯,我能影响号灯”是反着的,输入的时候要 小心识别 。
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <vector>
#include <map>
#include <queue>
#include <algorithm>
#include <math.h>
#include <cstdio>
using namespace std;
const int N = 30;
const double eps = 10e-8;
int n;
int start[N]; //开始状态
int stop[N]; //结束状态
//高斯消元模板
double a[N][N]; //增广矩阵
int gauss() {
int c, r; //当前列,行
// 1、枚举系数每一列
for (c = 0, r = 0; c < n; c++) {
// 2、找出系数最大的行
int t = r;
for (int i = r; i < n; i++) //行
if (abs(a[i][c]) > abs(a[t][c])) t = i;
// 3、最大系数为0,直接下一列
if (abs(a[t][c]) < eps) continue;
// 4、交换
if (r != t) // POJ中,如果二维数组,直接swap(a[t],a[r])会报编译错误,没办法,只好用了循环
for (int i = 0; i < N; i++) swap(a[t][i], a[r][i]);
// 5、倒序, 每项除a[r][c],化系数为1,处理的是方程左右两端,需要带着a[r][n]
for (int i = n; i >= c; i--) a[r][i] /= a[r][c];
// 6、用当前行将下面所有的列消成0
for (int i = r + 1; i < n; i++)
for (int j = n; j >= c; j--)
a[i][j] -= a[r][j] * a[i][c];
// 7、下一行
r++;
}
if (r < n) {
for (int i = r; i < n; i++)
if (abs(a[i][n]) > eps)
return -1; //无解
return n - r; //自由元个数
}
//倒三角,将已知解代入
for (int i = n - 2; i >= 0; i--)
for (int j = i + 1; j < n; j++)
a[i][n] -= a[i][j] * a[j][n];
//唯一解:0
return 0;
}
int main() {
int T;
cin >> T;
while (T--) {
cin >> n;
memset(a, 0, sizeof(a));
memset(start, 0, sizeof(start)); //初始化开始状态
memset(stop, 0, sizeof(stop)); //初始化终止状态
//输入起始状态(下标从0开始)
for (int i = 0; i < n; i++) cin >> start[i];
//输入终止状态(下标从0开始)
for (int i = 0; i < n; i++) cin >> stop[i];
//输入增广矩阵
int x, y;
while (cin >> x >> y && x != 0 && y != 0)
a[y - 1][x - 1] = 1; //反着存入y-1受x-1影响
for (int i = 0; i < n; i++) {
a[i][n] = start[i] ^ stop[i]; //状态变化 start^stop
a[i][i] = 1; //自己影响自己
}
//高斯消元模板
int t = gauss();
if (t == -1)
cout << "Oh,it's impossible~!!" << endl;
else
cout << (1 << t) << endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2018-06-21 全量脚本
2018-06-21 安装 sshpass
2018-06-21 The last packet sent successfully to the server was 0 milliseconds ago.[nutch---mysql ]
2017-06-21 记录一次统计首页MYSQL非常慢的解决过程