板子
图论
Tarjan
求强连通分量
int n, m, tot, top, cnt;
int dfn[N], low[N];
int q[N], ins[N], c[N];
vector<int> eg[N], scc[N], neg[N];
int cd[N];
void tarjan(int u){
dfn[u] = low[u] = ++tot;
q[++top] = u, ins[u] = 1;
for(auto x : eg[u]){
if(!dfn[x]){
tarjan(x);
low[u] = min(low[u], low[x]);
}
else if(ins[x]){
low[u] = min(low[u], dfn[x]);
}
}
if(dfn[u] == low[u]){
int e; cnt++;
do{
e = q[top--], ins[e] = 0;
c[e] = cnt, scc[cnt].push_back(e);
}while(u != e);
}
}
c[i]
表示第 i
个点的连通块编号, scc
储存每个连通块里的所有点
求割点
vector<int> g[N];
int n, m;
int tot, dfn[N], low[N], cnt;
int R, buc[N];
void tarjan(int u){
dfn[u] = low[u] = ++tot;
int son = 0;
for(auto v : g[u]){
if(!dfn[v]){
son++, tarjan(v), low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u] && u != R) cnt += !buc[u], buc[u] = 1;
}
else low[u] = min(low[u], dfn[v]);
}
if(son >= 2 && u == R) cnt += !buc[u], buc[u] = 1;
}
最短路
朴素Dijkstra
const int N = 505, M = 1e5 + 10;
int g[N][N], d[N], st[N];
int n, m;
int Dijkstra(){
memset(d, 0x3f, sizeof d);
d[1] = 0;
for(int i = 1;i <= n;i ++){
int tmp = 1e9, u;
for(int i = 1;i <= n;i ++)
if(!st[i] && tmp > d[i]) tmp = d[i], u = i;
st[u] = 1;
for(int i = 1;i <= n;i ++){
d[i] = min(d[i], d[u] + g[u][i]);
}
}
if(d[n] == 0x3f3f3f3f) return -1;
return d[n];
}
堆优化Dijkstra
const int N = 1e6;
typedef pair<int, int> PII;
int h[N], e[N], dist[N], st[N], w[N], ne[N], idx;
int n, m;
void add(int a, int b, int z){
e[idx] = b, ne[idx] = h[a], w[idx] = z, h[a] = idx++;
}
int Dijkstra(){
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, 1});
while(heap.size()){
PII tmp = heap.top();
heap.pop();
int u = tmp.second;
if(st[u]) continue;
st[u] = 1;
for(int i = h[u];i != -1;i = ne[i]){
int j = e[i];
if(dist[j] > dist[u] + w[i]){
dist[j] = dist[u] + w[i];
heap.push({dist[j], j});
}
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
Floyd
for (k = 1; k <= n; k++) {
for (x = 1; x <= n; x++) {
for (y = 1; y <= n; y++) {
f[x][y] = min(f[x][y], f[x][k] + f[k][y]);
}
}
}
Bellman-Ford
struct edge {
int v, w;
};
vector<edge> e[maxn];
int dis[maxn];
const int inf = 0x3f3f3f3f;
bool bellmanford(int n, int s) {
memset(dis, 63, sizeof(dis));
dis[s] = 0;
bool flag; // 判断一轮循环过程中是否发生松弛操作
for (int i = 1; i <= n; i++) {
flag = false;
for (int u = 1; u <= n; u++) {
if (dis[u] == inf) continue;
// 无穷大与常数加减仍然为无穷大
// 因此最短路长度为 inf 的点引出的边不可能发生松弛操作
for (auto ed : e[u]) {
int v = ed.v, w = ed.w;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
flag = true;
}
}
}
// 没有可以松弛的边时就停止算法
if (!flag) break;
}
// 第 n 轮循环仍然可以松弛时说明 s 点可以抵达一个负环
return flag;
}
SPFA
struct edge {
int v, w;
};
vector<edge> e[maxn];
int dis[maxn], cnt[maxn], vis[maxn];
queue<int> q;
bool spfa(int n, int s) {
memset(dis, 63, sizeof(dis));
dis[s] = 0, vis[s] = 1;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop(), vis[u] = 0;
for (auto ed : e[u]) {
int v = ed.v, w = ed.w;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
cnt[v] = cnt[u] + 1; // 记录最短路经过的边数
if (cnt[v] >= n) return false;
// 在不经过负环的情况下,最短路至多经过 n - 1 条边
// 因此如果经过了多于 n 条边,一定说明经过了负环
if (!vis[v]) q.push(v), vis[v] = 1;
}
}
}
return true;
}
匈牙利求二分图最大匹配
int n, tag;
int e[N][N], use[N], path[N];
int dfs(int u){
for(int i = 1; i <= n; i ++){
if(e[u][i] && use[i] != tag){
use[i] = tag;
if(path[i] == -1 || dfs(path[i])){
path[i] = u;
return 1;
}
}
}
return 0;
}
int sum = 0;
for(int i = 1; i <= n; i ++){
tag++;
if(dfs(i)) sum++;
}
拓扑排序
void topu_sort(){
queue<int> gs;
for(int i = 1; i <= cnt; i ++){
if(du[i] == 0){
gs.push(i);
}
}
while(gs.size()){
int t = gs.front(); gs.pop();
sx.push_back(t);
for(auto x : ng[t]){
du[x]--;
if(du[x] == 0){
gs.push(x);
}
}
}
}
网络流
EK算法
时间复杂度: 不过一般是远远达不到这个上界的,能够处理 规模的网络。
```cpp
#include<bits/stdc++.h>
using namespace std;
#define N 210
#define M 5010
#define int long long
int n, m, s, t;
int h[N], e[M * 2], ne[M * 2], w[M * 2], idx;
int g[N][N];
int maxf, pre[N], intc[N], vis[N];
void add(int a, int b, int c){
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int bfs(){
queue<int> q;
q.push(s);
memset(vis, 0, sizeof vis);
vis[s] = 1;
intc[s] = 0x3f3f3f3f;
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = h[u]; i != -1; i = ne[i]){
int v = e[i];
if(vis[v] || w[i] == 0) continue;
pre[v] = i;
intc[v] = min(intc[u], w[i]);
vis[v] = 1;
q.push(v);
if(v == t) return 1;
}
}
return 0;
}
void up(){
int now = t;
while(now != s){
int i = pre[now];
w[i] -= intc[t];
w[i ^ 1] += intc[t];
now = e[i ^ 1];
}
maxf += intc[t];
}
signed main(){
memset(h, -1, sizeof h);
// freopen("shuju.in", "r", stdin);
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> m >> s >> t;
for(int i = 1; i <= m; i ++){
int a, b, c;
cin >> a >> b >> c;
g[a][b] += c;
}
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++){
if(g[i][j]){
add(i, j, g[i][j]), add(j, i, 0);
}
}
}
while(bfs()) up();
cout << maxf;
}
Dinic
时间复杂度为 ,实际比这个快多了,一般能处理 规模的网络。用Dinic求解二分图最大匹配的时间复杂度为 ,同样实际会更快。
数学
矩阵快速幂
struct juzhen{
int a[5][5];
int n, m;
juzhen(){ //矩阵初始化
n = m = 0;
fill(a[0], a[0] + 5 * 5, 0);
}
void unit(int kn){ //构建单位矩阵
n = m = kn;
for(int i = 1; i <= n; i ++) a[i][i] = 1;
}
void init(){ //对于每个题目的初始矩阵
n = 3, m = 1;
a[1][1] = a[2][1] = a[3][1] = 1;
}
void zy(){ //每个题目的转移矩阵
n = 3, m = 3;
a[1][1] = a[1][3] = a[2][1] = a[3][2] = 1;
}
void out(){ //输出矩阵
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= m; j ++){
cout << a[i][j] << " ";
}cout << endl;
}
}
juzhen operator *(const juzhen &b){
juzhen res;
res.n = n, res.m = b.m;
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= b.m; j ++){
for(int k = 1; k <= m; k ++){
res.a[i][j] = (res.a[i][j] + a[i][k] * b.a[k][j] % mo) % mo;
}
}
}
return res;
}
};
juzhen qsm(juzhen base, int k){
juzhen res;
res.unit(3);
while(k){
if(k & 1) res = res * base;
base = base * base;
k >>= 1;
}
return res;
}
字符串
Hash
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 100010
#define mo1 1145141919811
#define mo2 200806040153
#define base 131
#define x first
#define y second
typedef pair<int, int> PII;
int n;
PII a[N];
char s[N];
int hash1(char s[]){
int n = strlen(s + 1), res = 0;
for(int i = 1; i <= n; i ++){
res = (res * base + (int)s[i]) % mo1;
}
return res;
}
int hash2(char s[]){
int n = strlen(s + 1), res = 0;
for(int i = 1; i <= n; i ++){
res = (res * base + (int)s[i]) % mo2;
}
return res;
}
signed main(){
// freopen("shuju.in", "r", stdin);
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i ++){
cin >> s + 1;
a[i].x = hash1(s);
a[i].y = hash2(s);
}
sort(a + 1, a + n + 1);
int ans = 1;
for(int i = 2; i <= n; i ++){
if(a[i].x != a[i - 1].x && a[i].y != a[i - 1].y){
ans++;
}
}
cout << ans;
return 0;
}
本文作者:星影流灿
本文链接:https://www.cnblogs.com/yduck/p/17738040.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步