闲话 10.10(有更新)

想到什么写什么


昨晚

CTH(大喊):HDK!

HDK(大喊):CTH!

CTH(愣了一下):干啥?


2-SAT

定义

给出若干个形如 \(a\lor b\) 的限制条件,询问是否有满足条件的一组解。

人话:给出 \(n\) 个集合,每个集合两个元素,再给定若干个限制条件 \(\left \langle a,b\right \rangle\) 表示 \(a\)\(b\) 矛盾,询问在这 \(n\) 个集合中各选一个能否满足所有限制条件。

思路

考虑转化限制条件。已知 \(a\lor b\) 为真,则当 \(\lnot a\) 为真时 \(b\) 必为真,简单推一下可得:

\[\lnot a\to b,\lnot b \to a \]

这样模型就构建出来了,我们可以将其转化成图来做。

考虑这样连边的含义,若起点为真则终点必为真,那么若成环则表示这些点同时为真或假,我们可以用 tarjan 将它们缩成一个点。

判断有无解的办法是看 \(a\)\(\lnot a\) 的点是否缩成同一个点,若是则显然无解,否则有解。

若要输出方案,一种合法的构造是判断 \(a\)\(\lnot a\) 缩点的先后,先缩为真。

实现

【模板】2-SAT

直接按思路做即可。

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{char ch = getchar();lx x = 0 , f = 1;for(;ch<'0'||ch>'9';ch = getchar()) if(ch == '-') f = -1;for(;ch>= '0' && ch<= '9';ch = getchar()) x = (x<<3) + (x<<1) + (ch^48);return x*f;
}
#undef lx
#define qr qr()
#define pii pair<int, int>
#define pil pair<int, ll>
#define fi first
#define se second
const int Ratio = 0;
const int N = 2e6 + 5;
int n, m;
int dfn[N], low[N], tot, bl[N], num;
int hh[N], to[N << 1], ne[N << 1], cnt;
stack<int> st;
namespace Wisadel
{void Wadd(int u, int v){to[++cnt] = v;ne[cnt] = hh[u];hh[u] = cnt;}void Wtarjan(int u){dfn[u] = low[u] = ++tot, st.push(u);for(int i = hh[u]; i != -1; i = ne[i]){int v = to[i];if(!dfn[v]){Wtarjan(v);low[u] = min(low[u], low[v]);}else if(!bl[v]) low[u] = min(low[u], dfn[v]);}if(dfn[u] == low[u]){++num;while(st.size()){int zc = st.top(); st.pop();bl[zc] = num;if(zc == u) break;}}}short main(){// freopen(".in", "r", stdin) , freopen(".out", "w", stdout);n = qr, m = qr;memset(hh, -1, sizeof hh);fo(i, 1, m){int x = qr, v1 = qr, y = qr, v2 = qr;if(v1 && v2) Wadd(x + n, y), Wadd(y + n, x);if(v1 && !v2) Wadd(x + n, y + n), Wadd(y, x);if(!v1 && v2) Wadd(x, y), Wadd(y + n, x + n);if(!v1 && !v2) Wadd(x, y + n), Wadd(y, x + n);}fo(i, 1, 2 * n) if(!dfn[i]) Wtarjan(i);bool can = 1;fo(i, 1, n) if(bl[i] == bl[i + n]){can = 0; break;}if(!can) puts("IMPOSSIBLE");else{puts("POSSIBLE");fo(i, 1, n) printf("%d ", (bl[i] < bl[i + n]));}return Ratio;}
}
int main(){return Wisadel::main();}

例题

[JSOI2010] 满汉全席

每一种食材不是满就是汉,比较能看出来是 2-SAT,看出来后就是纯板子了。

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{char ch = getchar();lx x = 0 , f = 1;for(;ch<'0'||ch>'9';ch = getchar()) if(ch == '-') f = -1;for(;ch>= '0' && ch<= '9';ch = getchar()) x = (x<<3) + (x<<1) + (ch^48);return x*f;
}
#undef lx
#define qr qr()
#define pii pair<int, int>
#define pil pair<int, ll>
#define fi first
#define se second
const int Ratio = 0;
const int N = 1e5 + 5;
int m, n;
int dfn[N], low[N], tot, bl[N], num;
int hh[N], to[N << 1], ne[N << 1], cnt;
stack<int> st;
namespace Wisadel
{void Wadd(int u, int v){to[++cnt] = v;ne[cnt] = hh[u];hh[u] = cnt;}void Wtarjan(int u){dfn[u] = low[u] = ++tot, st.push(u);for(int i = hh[u]; i != -1; i = ne[i]){int v = to[i];if(!dfn[v]){Wtarjan(v);low[u] = min(low[u], low[v]);}else if(!bl[v]) low[u] = min(low[u], dfn[v]);}if(dfn[u] == low[u]){num++;while(st.size()){int zc = st.top(); st.pop();bl[zc] = num;if(zc == u) break;}}}short main(){// freopen(".in", "r", stdin) , freopen(".out", "w", stdout);int T = qr;while(T--){n = qr, m = qr;cnt = num = tot = 0;memset(hh, -1, sizeof hh);memset(bl, 0, sizeof bl);memset(dfn, 0, sizeof dfn);fo(i, 1, m){string s1, s2; cin >> s1 >> s2;int l1 = s1.size(), l2 = s2.size();int v1 = 0, v2 = 0;fo(j, 1, l1 - 1) v1 = v1 * 10 + s1[j] - '0';fo(j, 1, l2 - 1) v2 = v2 * 10 + s2[j] - '0';if(s1[0] == 'm' && s2[0] == 'm') Wadd(v1 + n, v2), Wadd(v2 + n, v1);if(s1[0] == 'm' && s2[0] == 'h') Wadd(v1 + n, v2 + n), Wadd(v2, v1);if(s1[0] == 'h' && s2[0] == 'm') Wadd(v1, v2), Wadd(v2 + n, v1 + n);if(s1[0] == 'h' && s2[0] == 'h') Wadd(v1, v2 + n), Wadd(v2, v1 + n);}fo(i, 1, 2 * n) if(!dfn[i]) Wtarjan(i);bool can = 1;fo(i, 1, n) if(bl[i] == bl[i + n]){can = 0; break;}if(!can) puts("BAD");else puts("GOOD");}return Ratio;}
}
int main(){return Wisadel::main();}

发现要用到 tarjan,但是大部分忘了,所以复习。

Tarjan 求点双,缩点

感觉现阶段再看 tarjan 好理解了不少。

相关定义

\(dfn_u\) 为点 \(u\) 的 dfs 序,\(low_u\) 是点 \(u\) 能够回溯到的最早的已经在栈中的结点。

damn 你说的对,但我又把双连通分量和强连通分量搞混了。

思路

缩点

在 2-SAT 中,发现有些点构成了环,环上的点都互相能够到达,可以看做一个点来处理;其它的一些问题,也会有许多点共同构成一个集合的情况。我们把一个任意两点联通的子图称为一个强连通分量。考虑怎么求出一个图的强连通分量。

直接 dfs 图的每个点,并让遍历到的点入栈。当找到一个强连通分量时就出栈。这样我们搜索时会有三种情况:

  • 遍历到的点没有 dfs 序,即未遍历过,那么直接遍历该点,并用该点的 \(low\) 值更新当前点的 \(low\) 值。

  • 遍历到的点有 dfs 序,但当前不存在于一个已搜到的连通分量内,那么根据定义此时该点必在栈中,用该点的 \(dfn\) 值更新当前点的 \(low\) 值。

  • 遍历到的点有 dfs 序,存在于一个连通分量内,已经处理完了,所以不理。

这样操作后,考虑对于一个连通分量,有且仅有其中第一个被遍历到的点满足 \(dfn_u=low_u\),其它的点根据强连通分量的定义都能回溯到该点即 \(dfn_v\gt low_v=dfn_u\),所以回溯时判断二者是否相等即可判断是否该点与栈内在该点上方的点构成一个强连通分量。

求点双

点双概念:在一个点双中,删去任意一个点,其余点仍联通。与之相反的,割点的概念:在一个联通图中,删去该点,其余部分不再联通。

那么我们找到割点就相当于找到了点双。

那么考虑怎么找割点。若当前点是割点,那么其所有子节点都应有 \(low_v\ge dfn_u\)。那么我们直接将此时栈内点 \(v\) 及以上的点全部出栈为一个点双,然后再把当前点加入即可。

注意特判根节点和独立节点的情况。

实现

缩点

例题:所有 2-SAT 的题目。

不同的题可能有不同的细节,但大体上是一样的。

点击查看代码
    void Wtarjan(int u){dfn[u] = low[u] = ++tot, st.push(u);for(int i = hh[u]; i != -1; i = ne[i]){int v = to[i];if(!dfn[v]){Wtarjan(v);low[u] = min(low[u], low[v]);}else if(!bl[v]) low[u] = min(low[u], dfn[v]);}if(dfn[u] == low[u]){++num;while(st.size()){int zc = st.top(); st.pop();bl[zc] = num;if(zc == u) break;}}}

点双

求点双模板

纯板子,按上述思路实现即可。

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{char ch = getchar();lx x = 0 , f = 1;for(;ch<'0'||ch>'9';ch = getchar()) if(ch == '-') f = -1;for(;ch>= '0' && ch<= '9';ch = getchar()) x = (x<<3) + (x<<1) + (ch^48);return x*f;
}
#undef lx
#define qr qr()
#define pii pair<int, int>
#define pil pair<int, ll>
#define fi first
#define se second
const int Ratio = 0;
const int N = 5e5 + 5, M = 2e6 + 5;
int n, m, num;
int dfn[N], low[N], tot;
int hh[N], to[M << 1], ne[M << 1], cnt;
stack<int> st;
vector<int> ans[N];
namespace Wisadel
{void Wadd(int u, int v){to[++cnt] = v;ne[cnt] = hh[u];hh[u] = cnt;}void Wtarjan(int u, int fa){int son = 0;dfn[u] = low[u] = ++tot, st.push(u);for(int i = hh[u]; i != -1; i = ne[i]){int v = to[i];if(v == fa) continue;if(!dfn[v]){son++;Wtarjan(v, u);low[u] = min(low[u], low[v]);if(low[v] >= dfn[u]){++num;while(st.size()){int zc = st.top(); st.pop();ans[num].push_back(zc);if(zc == v) break;}ans[num].push_back(u);}}else low[u] = min(dfn[v], low[u]);}if(fa == 0 && son == 0) ans[++num].push_back(u);}short main(){// freopen(".in", "r", stdin) , freopen(".out", "w", stdout);n = qr, m = qr;memset(hh, -1, sizeof hh);fo(i, 1, m){int a = qr, b = qr;Wadd(a, b), Wadd(b, a);}fo(i, 1, n) if(!dfn[i]) Wtarjan(i, 0);printf("%d\n", num);fo(i, 1, num){printf("%d ", ans[i].size());for(int j : ans[i]) printf("%d ", j);puts("");}return Ratio;}
}
int main(){return Wisadel::main();}

体育课

羽毛球教练:咱们这人数有点多了啊,好多别的课的都跑过来了,所以点一下人数,点到名的站这边来。

Ratio:int_R 没来,他是不是羽毛球的?

5k:正确的,你一会就报他名就行。

Aqr(对 CTH):9G 也报的羽毛球,你一会报他名去。

“9G!”

(CTH 冲了过去)

【省略点名的同学和其它熟知 9G 的人的疑惑目光】

“int_R!”

(Ratio 冲了过去,发现顶真也在)

教练(对 Ratio):你叫什么?

Ratio:int_R。(跑

然后顶真就坠机了。

5k:上体育课先练习随机映射。

Ratio:这是离散化数组开小了。

5k:在范围内的数不变,不在范围内的数随机赋值然后到顶真直接越界返回错误指针了是吧。


晚饭

Ratio(对 HDK):没吃饱,再去买点。

(中途碰到一个大概率见过的学妹)

学妹(对另一个):哇,饮月(指我带的徽章)!我又看到他了。

回来后告诉 HDK 全过程

Ratio:这种感觉还挺爽的。

HDK:😡😡😡


大概率不会再更了

完结撒花~

image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/811217.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024秋软件工程结对作业(第二次)

软件工程 班级链接:https://edu.cnblogs.com/campus/fzu/SE2024作业要求链接 https://edu.cnblogs.com/campus/fzu/SE2024/homework/13281作业目标 开发一套跨专业合作平台,为大学生提供发起和参与跨学科项目的渠道。学号 102201313Github项目地址 https://github.com/KeepUp…

06-蓝图实战(图书数据搜索与查询),编写get和post请求,同时应用WTForms参数验证

需求:之前的路由请求格式,不是通用的请求格式,转化为get 和 post请求之后,可以通过request方法获取其中的参数 参考格式 04-使用 Flask 框架实现 POST和GET接口 - 马铃薯1 - 博客园 (cnblogs.com)@web.route(/book/search/<q>) def search(q):pass 第三方插件库,WT…

2024.9.30 CSP

模拟赛 赛后看着分哗啦啦的往下掉。 T1 median 找中位数,赛时假做法 A 了, 没想到直接搜。。。code #include<bits/stdc++.h> using namespace std; const int N = 1e5+5,mod = 998244353; int n; int a[6][N],ans,f[6][4]; unordered_map<int,bool> mp; int dfs…

VMware Workstation 17.6.1 发布下载,修复 4 个已知问题

VMware Workstation 17.6.1 发布下载,修复 4 个已知问题VMware Workstation 17.6.1 发布下载,修复 4 个已知问题 VMware Workstation 17.6.1 Pro for Windows & Linux - 领先的免费桌面虚拟化软件 基于 x86 的 Windows、Linux 桌面虚拟化软件 请访问原文链接:https://sy…

android开发编译openssl源代码生成libcrypto.so和libssl.so两个动态库用于android ndk项目开发使用

openssl编译本篇文章的操作是在Linux环境之下,在虚拟机ubuntu 20版本上操作的步骤1. openssl下载解压tar包openssl下载地址:https://openssl-library.org/source/下载完解压:tar -zxvf openssl-3.3.2.tar.gz // 我这里下载openssl-3.3.2.tar.gz版本2. 编译openssl库,得到l…

MySQL下载、安装与配置

MySQL下载、安装与配置下载MySQL 1、进入MySQL官网 2、点击 Products,再点击 MySQL Community Server3、选择MySQL版本,点击 Go to Download Page4、点击 Download 下载MySQL安装程序5、点击 No thanks, just start my download,等待下载安装MySQL 1、双击运行下载的安装程序…

web端ant-design-vue Upload 手动实现文件上传使用小节

web端ant-design-vue Upload 手动实现文件上传使用小节。最近在项目开发中用到了手动实现文件上传的组件,之前都是自动上传把返回的文件信息保存到服务器。手动上传相对复杂一下,我把遇到的一些问题整理记录一下,有需要的朋友可以避免走弯路! 1、文件上传需要用formdata格式…

记一次k8s挂载configmap配置文件识别为文件夹的错误

错误表现 挂载.env为配置文件时被识别成一个文件夹而不是一个文件错误原因 创建configmap的时候原始文件使用的是env解决方式 创建configmap的时候需要使用的文件需要修改文件名为挂载的文件名一致 例如本次挂载的文件名是.env则需要在创建configmap的时候原始文件名修改为.evn…

开源项目更新|WPF/Uno Platform/WinUI 3三个版本的《英雄联盟客户端》

为了统一WPF/WinUI3/Uno仓库的项目架构,我们基于.NET Standard 2.0设计了一个可在所有平台上运行的框架,无需依赖第三方库。这个框架直接实现了项目分散化、模块化、视图注入、依赖注入、单例模式和MVVM等基于XAML的项目架构所需功能。采用这种方法,我们可以在不同版本(如WPF、…

简明线性回归算法中的最小二乘法

我们来通过一个具体的例子说明线性回归算法中最小二乘法如何确定模型参数。 示例:房价预测 假设我们想用房子的面积(平方英尺)来预测房价(美元)。我们有以下数据集:面积(平方英尺)房价(美元)800 150,0001000 200,0001200 210,0001500 280,0001. 建立模型 我们假设房价…

简明线性回归算法

线性回归是一种用于预测和建模的统计方法,旨在通过建立输入变量(特征)与输出变量(目标)之间的线性关系来进行分析。下面我们通过一个简单易懂的例子来说明线性回归的详细过程。 例子:预测房价 假设你是一名房地产经纪人,想要根据房子的面积(平方英尺)来预测房子的价格…