20240916总结

news/2024/9/18 14:30:19/文章来源:https://www.cnblogs.com/roselu/p/18416600

不积跬步,无以千里。

这两天主要是复习了图的连通性相关的题+听了youwike哥哥讲课。

先是复习了缩点,割点,割边,点双,边双,2-SAT,感觉比较需要注意的是割点的那个第一个节点的判断,写题的时候总是容易忘。然后又写了几道练习题。

  • 缩点
#include <iostream>
#include <cstring>using namespace std;
const int N = 1e5 + 10;int n, m, tot, cnt, top, scc, ans;
int a[N], s[N], sta[N], x[N], y[N], f[N];
int head[N], dfn[N], low[N], col[N];
bool vis[N];
struct Map { int to, nxt; } e[N << 1];void add(int u, int v) {e[++tot] = {v, head[u]};head[u] = tot;
}void tarjan(int u) {low[u] = dfn[u] = ++cnt;vis[u] = 1, sta[++top] = u;for(int i = head[u]; i; i = e[i].nxt) {int v = e[i].to;if(!dfn[v]) {tarjan(v);low[u] = min(low[u], low[v]);} else if(vis[v]) low[u] = min(low[u], dfn[v]);}if(dfn[u] == low[u]) {scc++;while(sta[top + 1] != u) {col[sta[top]] = scc;s[scc] += a[sta[top]];vis[sta[top--]] = 0;}}
}void dfs(int x) {if(f[x]) return;f[x] = s[x];int maxx = 0;for(int i = head[x]; i; i = e[i].nxt) {int v = e[i].to;if(!f[v]) dfs(v);maxx = max(maxx, f[v]);}f[x] += maxx;
}int main() {cin >> n >> m;for(int i = 1; i <= n; ++i) cin >> a[i];for(int i = 1, u, v; i <= m; ++i)cin >> x[i] >> y[i], add(x[i], y[i]);for(int i = 1; i <= n; ++i)if(!dfn[i]) tarjan(i);for(int i = 1; i <= tot; ++i) e[i] = {0, 0};for(int i = 1; i <= n; ++i) head[i] = 0;tot = 0;for(int i = 1; i <= m; ++i) if(col[x[i]] != col[y[i]]) add(col[x[i]], col[y[i]]);for(int i = 1; i <= scc; ++i) {if(!f[i]) dfs(i), ans = max(ans, f[i]);}cout << ans << endl;return 0;
}
  • 点双
#include <iostream>
#include <vector>using namespace std;
const int N = 4e6 + 10;int n, m, tot, top, cnt, scc;
int s[N];
int head[N], dfn[N], low[N];
vector <int> ans[N];
struct Map { int to, nxt; } e[N << 1];void add(int u, int v) {e[++tot] = {v, head[u]};head[u] = tot;
}void tarjan(int u, int fa) {int son = 0;low[u] = dfn[u] = ++cnt;s[++top] = u;for(int i = head[u]; i; i = e[i].nxt) {int v = e[i].to;if(!dfn[v]) {son++, tarjan(v, u);low[u] = min(low[u], low[v]);if(low[v] >= dfn[u]) {scc++;while(s[top + 1] != v) ans[scc].push_back(s[top--]);ans[scc].push_back(u);}} else if(v != fa) low[u] = min(low[u], dfn[v]);}if(fa == 0 && son == 0) ans[++scc].push_back(u);
}int main() {cin >> n >> m;for(int i = 1, u, v; i <= m; ++i)cin >> u >> v, add(u, v), add(v, u);for(int i = 1; i <= n; ++i)if(!dfn[i]) top = 0, tarjan(i, 0);cout << scc << endl;for(int i = 1; i <= scc; ++i) {cout << ans[i].size() << ' ';for(int j = 0; j < ans[i].size(); ++j) cout << ans[i][j] << ' ';cout << endl;}return 0;
}
  • 2-SAT
#include <iostream>using namespace std;
const int N = 2e6 + 10;int n, m, tot, cnt, scc, top;
int head[N], dfn[N], low[N];
int s[N], col[N];
bool vis[N];
struct Map { int to, nxt; } e[N << 1];void add(int u, int v) {e[++tot] = {v, head[u]};head[u] = tot;
}void tarjan(int u) {low[u] = dfn[u] = ++cnt;vis[u] = 1, s[++top] = u;for(int i = head[u]; i; i = e[i].nxt) {int v = e[i].to;if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);else if(vis[v]) low[u] = min(low[u], dfn[v]);}if(low[u] == dfn[u]) {++scc;while(u != s[top + 1]) {col[s[top]] = scc;vis[s[top--]] = 0;}}
} int main() {cin >> n >> m;for(int i = 1, u, v, vu, vv; i <= m; ++i) {cin >> u >> vu >> v >> vv;add(u + n * (vu & 1), v + n * (vv ^ 1));add(v + n * (vv & 1), u + n * (vu ^ 1));}for(int i = 1; i <= (n << 1); ++i) if(!dfn[i]) tarjan(i);for(int i = 1; i <= n; ++i)if(col[i] == col[n + i]) return cout << "IMPOSSIBLE" << endl, 0;cout << "POSSIBLE" << endl;for(int i = 1; i <= n; ++i)cout << (col[i] < col[n + i]) << ' ';return 0;
}
  • 满汉全席
    \(m\)\(h\)看成两个对立的限制然后直接像2-SAT一样建图就行了,要注意的是对于每组数据都要全部初始化。
#include <iostream>
#include <cstring>using namespace std;
const int N = 2e6 + 10;int T, n, m, tot, cnt, scc, top;
int head[N], dfn[N], low[N];
int s[N], col[N];
char s1[110], s2[110];
bool vis[N];
struct Map { int to, nxt; } e[N << 1];void add(int u, int v) {e[++tot] = {v, head[u]};head[u] = tot;
}void tarjan(int u) {low[u] = dfn[u] = ++cnt;vis[u] = 1, s[++top] = u;for(int i = head[u]; i; i = e[i].nxt) {int v = e[i].to;if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);else if(vis[v]) low[u] = min(low[u], dfn[v]);}if(low[u] == dfn[u]) {++scc;while(u != s[top + 1]) {col[s[top]] = scc;vis[s[top--]] = 0;}}
} void Main() {cin >> n >> m;for(int i = 1; i <= tot; ++i) e[i] = {0, 0};memset(head, 0, sizeof(head)), memset(dfn, 0, sizeof(dfn));memset(low, 0, sizeof(low)), memset(s, 0, sizeof(s));memset(col, 0, sizeof(col)), memset(vis, 0, sizeof(vis));tot = cnt = scc = top = 0;for(int i = 1, u, v, vu, vv; i <= m; ++i) {cin >> s1 >> s2, u = v = 0;int lu = strlen(s1), lv = strlen(s2);vu = (s1[0] == 'm'), vv = (s2[0] == 'm');for(int j = 1; j < lu; ++j) u = u * 10 + s1[j] - '0';for(int j = 1; j < lv; ++j) v = v * 10 + s2[j] - '0';add(u + n * (vu & 1), v + n * (vv ^ 1));add(v + n * (vv & 1), u + n * (vu ^ 1));}for(int i = 1; i <= (n << 1); ++i) if(!dfn[i]) tarjan(i);for(int i = 1; i <= n; ++i)if(col[i] == col[n + i]) return cout << "BAD" << endl, void();cout << "GOOD" << endl;
}int main() {cin >> T;while(T--) Main();return 0;
}
  • Redundant Paths G
    因为是双向边,所以缩点之后就肯定是一棵树,然后要至少度数是2,所以最好的方法就是每两个缩点之后的叶子节点连边,所以答案就是\((s-1)/2\)(s是叶子节点个数)
#include <iostream>
#include <vector>using namespace std;
const int N = 2e6 + 10;int n, m, tot = 1, top;
int cnt, scc, ans;
int head[N], u[N], v[N], d[N];
int dfn[N], low[N], s[N], col[N];
bool vis[N];
struct Map { int to, nxt; bool flag; } e[N * 2];void add(int u, int v) {e[++tot] = {v, head[u], 0};head[u] = tot;
}void tarjan(int u) {low[u] = dfn[u] = ++cnt;s[++top] = u;for(int i = head[u]; i; i = e[i].nxt) {if(vis[i]) continue;vis[i] = vis[i ^ 1] = 1;int v = e[i].to;if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);else low[u] = min(low[u], dfn[v]);}if(low[u] == dfn[u]) {++scc;while(u != s[top + 1]) col[s[top--]] = scc;}
}int main() {cin >> n >> m;for(int i = 1; i <= m; ++i) cin >> u[i] >> v[i], add(u[i], v[i]), add(v[i], u[i]);for(int i = 1; i <= n; ++i)if(!dfn[i]) tarjan(i);for(int i = 1; i <= m; ++i) if(col[u[i]] != col[v[i]]) d[col[u[i]]]++, d[col[v[i]]]++;for(int i = 1; i <= scc; ++i) if(d[i] == 1) ans++;cout << (ans + 1) / 2 << endl;return 0;
}
  • Running In The Sky
    缩点板子题,就多维护一个路径最大值就行了。
#include <iostream>
#include <vector>using namespace std;
const int N = 2e6 + 10;int n, m, tot = 1, top;
int cnt, scc, ans;
int head[N], u[N], v[N], d[N];
int dfn[N], low[N], s[N], col[N];
bool vis[N];
struct Map { int to, nxt; bool flag; } e[N * 2];void add(int u, int v) {e[++tot] = {v, head[u], 0};head[u] = tot;
}void tarjan(int u) {low[u] = dfn[u] = ++cnt;s[++top] = u;for(int i = head[u]; i; i = e[i].nxt) {if(vis[i]) continue;vis[i] = vis[i ^ 1] = 1;int v = e[i].to;if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);else low[u] = min(low[u], dfn[v]);}if(low[u] == dfn[u]) {++scc;while(u != s[top + 1]) col[s[top--]] = scc;}
}int main() {cin >> n >> m;for(int i = 1; i <= m; ++i) cin >> u[i] >> v[i], add(u[i], v[i]), add(v[i], u[i]);for(int i = 1; i <= n; ++i)if(!dfn[i]) tarjan(i);for(int i = 1; i <= m; ++i) if(col[u[i]] != col[v[i]]) d[col[u[i]]]++, d[col[v[i]]]++;for(int i = 1; i <= scc; ++i) if(d[i] == 1) ans++;cout << (ans + 1) / 2 << endl;return 0;
}
  • 菜肴制作
    容易发现,如果直接按照限制做的话是不对的,因为不是要最后字典序最小,而是要当前没有输出的数尽量靠前。但是可以发现越大的书越靠后肯定是不劣的,所以只用倒着拓扑就行了。
#include <iostream>
#include <vector>
#include <queue>using namespace std;
const int N = 1e5 + 10;int T, n, m, cnt;
int in[N], ans[N];
vector <int> v[N];
priority_queue <int> q;void Main() {cin >> n >> m;cnt = 0;for(int i = 1; i <= n; ++i)in[i] = ans[i] = 0, v[i].clear();for(int i = 1, u, vv; i <= m; ++i) {cin >> u >> vv;in[u]++, v[vv].push_back(u);}for(int i = 1; i <= n; ++i)if(!in[i]) q.push(i);while(!q.empty()) {int u = q.top();q.pop();for(int i = 0; i < v[u].size(); ++i) {int y = v[u][i];in[y]--;if(!in[y]) q.push(y);}ans[++cnt] = u;}if(cnt < n) return cout << "Impossible!" << endl, void();for(int i = cnt; i; --i) cout << ans[i] << ' ';cout << endl;
}int main() {cin >> T;while(T--) Main();return 0;
}

感觉缩点很好使啊,就是考试没见过

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

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

相关文章

MobaXterm 密钥生成器

1、MobaXterm 密钥生成器,代码仓库地址: https://gitcode.com/gh_mirrors/mo/MobaXterm-keygen/blob/master/MobaXterm-Keygen.py 2、也可以用我打包好的exe程序,不用安装python环境: https://pan.baidu.com/s/1jo85pQc_kfWhcYmZcc49CQ 提取码:ws10 3、源码:#/usr/bin/e…

Linux引导启动程序(boot)

概述 本章主要描述boot/目录中的三个汇编代码文件,见列表6-1所示。正如在前一章中提到的,这三个文件虽然都是汇编程序,但却使用了两种语法格式。bootsect.s和setup.s是实模式下运行的16位代码程序,采用近似于Intel的汇编语言语法并且需要使用Intel 8086汇编编译器和连接器as86和…

9、const修饰指针

*代表指针,这样有助于记忆和区别这三种

day1闯关作业小结[linux基础知识]

完成SSH连接与端口映射并运行hello_world.py 1.进入InternStudio https://studio.intern-ai.org.cn/, 创建个人开发机2.使用密码进行SSH远程连接并进行端口映射3.运行hello_world.py

白云龙期货投资-第三讲

反转形态**头肩底(顶) 双底(顶) 三重底(顶) 圆弧底(顶)**持续形态**三角形 旗形 楔行 扩散三角形 收缩三角形**K线形态(反转形态,持续形态) 反转形态 头肩底(顶) 双底(顶) 三重底(顶) 圆弧底(顶) 持续形态 三角形 旗形 楔行 扩散三角形 收缩三角形 头肩顶头肩底双底(双顶)下…

java的方法和数组

什么是方法呢? 就类似c语言的函数 返回类型 方法名 形式参数列表 方法名最好使用小驼峰的形式,在java中方法不可以嵌套使用, 方法的调用: 就是在main方法里面写上调用的方法名加上需要传输的值,创建一个和方…

mongo集群同步数据异常,手动同步节点副本数据

转载请注明出处: 数据同步方案当副本集节点的复制进程落后太多,以至于主节点覆盖了该节点尚未复制的 oplog 条目时,副本集节点就会变为“陈旧”。节点跟不上,就会变得“陈旧”。出现这种情况时,必须删除副本集节点的数据,然后执行初始同步,从而完全重新同步该节点。 Mon…

7、函数分文件编写

1、swap.h2、swap.cpp3、使用

三、redis之strings类型

strings是redis中使用最多的类型。 redis官网中是这么描述strings的: Redis strings store sequences of bytes, including text, serialized objects, and binary arrays. 可以看到Redis strings保存的是sequences of bytes,也就是字节序列。不仅可以保存字符串,而且还可以…

排队论——数学模型和绩效指标精解

排队论最早由丹麦工程师Agner Krarup Erlang于1910年提出,旨在解决自动电话系统的问题,成为话务理论的奠基石。Erlang通过研究电话呼叫的随机到达和服务时间,推导出著名的埃尔朗电话损失率公式,用于计算电话系统的呼叫阻塞率,揭示了排队现象的本质。Erlang之后,排队论得到…

本地文件包含漏洞详解与CTF实战

1. 本地文件包含简介 1.1 本地文件包含定义 本地文件包含是一种Web应用程序漏洞,攻击者通过操控文件路径参数,使得服务器端包含了非预期的文件,从而可能导致敏感信息泄露。 常见的攻击方式包括:包含配置文件、日志文件等敏感信息文件,导致信息泄露。 包含某些可执行文件或…