一直走,没得走了以后,回头换个方向再一直走
使用 stack
一次走一层,层层扩展
具有最短性
使用 queue
const int N = 1e5 + 10;
int h[N], e[N], ne[N], idx;
void add(int a, int b) {
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
bool vis[N];
void dfs(int u) {
vis[u] = true;
for (int i = h[u]; i != -1; i = ne[i]) {
if (vis[e[i]]) dfs(i);
}
}
int bfs() {
queue<int> q;
q.push(1);
while (q.size()) {
int u = q.front(); q.pop();
for (int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if (!vis[v]) {
q.push(v);
dis[v] = dis[u] + 1;
}
}
}
return dis[n];
}
- 初始化 dis 数组,dis[1] = 0, dis[i] = +∞
- 从 1 到 n
- t <- 不在 S 中,距离最近的点
- S <- t
- 用 t 更新其他点的距离
int dijsktra() {
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
for (int i = 0; i < n; i++) {
int t = -1;
for (int j = 1; j <= n; j++)
if (!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
st[t] = true;
for (int j = 1; j <= n; j++)
dist[j] = min(dist[j], dist[t] + g[t][j]);
}
if (dist[n] == INF) return -1;
return dist[n];
}
- 初始化 dis 数组,dis[1] = 0, dis[i] = +∞
- 从 1 到 n
- t <- 不在 S 中,距离最近的点(利用堆维护最小值)
- S <- t
- 用 t 更新其他点的距离
const int N = 2e5 + 10;
int h[N], hi[N], ih[N], cnt;
int n;
const int INF = 0x3f3f3f3f;
inline int lc(int x) {
return x << 1;
}
inline int rc(int x) {
return (x << 1) + 1;
}
inline void h_swap(int x, int y) {
swap(h[x], h[y]);
swap(hi[x], hi[y]);
swap(ih[hi[x]], ih[hi[y]]);
}
inline void up(int i) {
while (i >> 1 && h[i] < h[i >> 1]) {
h_swap(i, i >> 1);
i >>= 1;
}
}
void down(int i) {
int t = i;
if (lc(i) <= cnt && h[lc(i)] < h[t]) t = lc(i);
if (rc(i) <= cnt && h[rc(i)] < h[t]) t = rc(i);
if (i != t) {
h_swap(i, t);
down(t);
}
}
int ne[N], he[N], idx;
pair<int, int> e[N];
void add(int u, int v, int w) {
e[idx].first = v;
e[idx].second = w;
ne[idx] = he[u];
he[u] = idx++;
}
void update(int i, int v) {
h[ih[i]] = v;
up(ih[i]);
down(ih[i]);
}
void remove() {
h_swap(1, cnt--);
down(1);
}
int dist[N];
int dijkstra() {
for (int i = 1; i <= n; i++) {
h[++cnt] = INF;
ih[i] = cnt;
hi[cnt] = i;
}
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
update(ih[1], 0);
for (int i = 0; i < n; i++) {
int u = hi[1];
int t = h[1];
// cout << u << "|" << t << endl;
for (int i = he[u]; i != -1; i = ne[i]) {
int v = e[i].first;
int w = e[i].second;
if (dist[v] > dist[u] + w) {
update(v, dist[u] + w);
dist[v] = dist[u] + w;
// cout << v << " " << dist[u] + w << endl;
}
}
remove();
}
if (dist[n] == INF) return -1;
return dist[n];
}
typedef pair<int, int> PII;
int dijsktra() {
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, 1});
for (int i = 0; i < n; i++) {
auto t = heap.top(); heap.pop();
int ver = t.second; distance = t.first;
if (st[ver]) continue;
st[ver] = true;
for (int i = h[ver]; i != -1; i = ne[i]) {
int v = e[i];
if (dist[v] > distance + w[i]) {
dist[v] = distance + w[i];
heap.push({dist[v], v});
}
}
}
if (dist[n] == INF) return -1;
return dist[n];
}
- 迭代 n 次
- 对于所有边 u, v, w
- dist[v] = min(dist[v], dist[a] + w);(松弛)
算法存在负环可能不存在 最短路,但可以求出,路径长度为 k 的最短路
int bellmanford() {
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
for (int i = 0; i < k; i++) {
memcpy(backup, dist, sizeof dist); // 防止串联
for (int j = 0; j < m; j++) {
int uu = u[j], vv = v[j], ww = w[j];
dist[vv] = min(dist[vv], backup[uu] + ww);
}
}
if (dist[n] > INF / 2) return -1;
return dist[n];
}
- while queue 不为空
- t <- q.front()
- 更新 t 的所有出边 (t, b, c)
- queue <- b
相当于在bellmanford算法上,加了一层优化
- dist[v] 想更新,一定得 dist[u] 更新之后,才会更新
- 利用一个队列存储待更新的点,利用 st 数组,让队列里每个点只出现一次
int spfa() {
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
queue<int> q;
st[1] = true;
q.push(1);
while (q.size()) {
int t = q.front(); q.pop();
st[t] = false;
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];
if (dist[j] <= dist[t] + w[i]) continue;
dist[j] = dist[t] + w[i];
if (st[j]) continue;
st[j] = true;
q.push(j);
}
}
if (dist[n] == INF) return -1;
return dist[n];
}
动态规划
dp[k, i, j] = dp[k - 1, i, j] + dp[k, i, j]
利用前 k-1 条边 ,结合第 k 条边进行松弛
void floyd() {
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
}
算法流程
- dist[i] <- +∞
- 迭代 n 次
- t <- 到集合距离最近的点
- 用 t 更新其他点到集合的距离
- S <- t
算法模板
int prim() {
memset(dist, 0x3f, sizeof dist);
int res = 0;
for (int i = 0; i < n; i++) {
int t = -1;
for (int j = 1; j <= n; j++)
if (!st[j] && (t == -1 || dist[j] < dist[t])) t = j;
if (i && dist[t] == INF) return INF;
if (i) res += dist[t]; // 防止负权自环更新 dist[t]
for (int j = 1; j <= n; j++)
dist[j] = min(dist[j], g[t][j]);
st[t] = true;
}
return res;
}
算法流程
- 对所有边按权重从小到大排序
- 枚举每条边 (a, b, c)
- 如果 a b 在一个集合,跳过
- 如果 a b 不在一个集合,两个集合合并(做 n - 1 次)
int find(int x) {
return x == p[x] ? x : p[x] = find(p[x]);
}
void combine(int x, int y) {
p[find(x)] = find(y);
}
int kruskal() {
sort(e, e + m, [](auto a, auto b) {
return a.c < b.c;
});
for (int i = 1; i <= n; i++) p[i] = i;
int cnt = 1;
int res = 0;
for (int i = 0; i < m && cnt < n; i++) {
auto ee = e[i];
if (find(ee.a) != find(ee.b)) {
cnt++;
res += ee.c;
combine(ee.a, ee.b);
}
}
if (cnt == n) return res;
return INF;
}
一个图是二分图,当且仅当图中没有奇数环
bool dfs(int u, int c) {
color[u] = c;
for (int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if (!color[v]) {
if (!dfs(v, 3 - c)) return false;
} else if (color[v] == color[u]) {
return false;
}
}
return true;
}
- 对于每个 左半部分的点,试图匹配右半部分
- 如果能匹配,那就匹配,res++
- 如果不能匹,递归使已经匹配好的点匹配别的,再尝试匹配
- 成功,那就匹配,res++ 2. 失败,这个点就跳过
#include <iostream>
#include <cstring>
using namespace std;
const int N = 500 + 10;
const int M = 1e5 + 10;
int n1, n2, m;
int h[N], e[M], ne[M], idx;
bool st[N];
int match[N];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
bool find(int x) {
for (int i = h[x]; i != -1; i = ne[i]) {
int j = e[i];
if (!st[j]) {
st[j] = true;
if (match[j] == 0 || find(match[j])) {
match[j] = x;
return true;
}
}
}
return false;
}
int main() {
memset(h, -1, sizeof h);
cin >> n1 >> n2 >> m;
while (m--) {
int a, b;
cin >> a >> b;
add(a, b);
}
int res = 0;
for (int i = 1; i <= n1; i++) {
memset(st, false, sizeof st);
if (find(i)) res++;
}
cout << res << endl;
}