#include <bits/stdc++.h>
#define ll long long
#define mem(s, i) memset(s, i, sizeof(s))
#define pb push_back
#define pii pair<int, int>
#define endl "\n"
using namespace std;
const int N = 1000 + 10;
const int M = 3e5 + 10;
const ll inf = 1e9;
堆优化dijkstra
struct edge {
int to, dis, next;
};
struct node {
int dis;
int pos;
bool operator <( const node &x )const {
return x.dis < dis;
}
};
edge e[N];
int head[N], dis[N], cnt = 0;
bool vis[N];
int n, m, s;
void init() {
for (int i = 0; i <= n; i++) {
dis[i] = INF;
head[i] = -1;
}
}
void add_edge(int u, int v, int d) {
e[cnt].dis = d;
e[cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt++;
}
void dijkstra() {
mem(dis,0x3f);
priority_queue<node> pq;
dis[s] = 0;
pq.push({0, s});
while (!pq.empty()) {
node t = pq.top();
pq.pop();
int x = t.pos, d = t.dis;
if (vis[x]) continue;
vis[x] = 1;
for (int i = head[x]; i != -1; i = e[i].next) {
int y = e[i].to;
if (dis[y] > dis[x] + e[i].dis) {
dis[y] = dis[x] + e[i].dis;
if (!vis[y]) {
pq.push({dis[y], y});
}
}
}
}
}
void solve() {
cin >> n >> m >> s;
init();
for (int i = 1; i <= m; i++) {
int u, v, d;
cin >> u >> v >> d;
add_edge(u, v, d);
}
dijkstra();
for(int i = 1;i <= n;i++) {
cout << dis[i] << " ";
}
}
拓扑排序
int n, m, cnt = 0, res;
int deg[N], head[N];
struct Edge {
int to;
int next;
} edge[N];
void add_edge(int u, int v) {
edge[cnt].to = v; //终点
edge[cnt].next = head[u];//以u为起点上一条边的编号,也就是与这个边起点相同的上一条边的编号
head[u] = cnt++;//更新以u为起点上一条边的编号
}
void topsort() {
priority_queue<int, vector<int>, greater<int>> pq;
for(int i = 1;i <= n;i++) {
if(deg[i] == 0) pq.push(i);
}
while(!pq.empty()){
int t = pq.top();
pq.pop();
deg[t] = -1;
for(int i = head[t];i != -1;i = edge[i].next) {
deg[edge[i].to]--;
if(deg[edge[i].to] == 0) {
pq.push(edge[i].to);
}
}
}
}
SPFA
struct edge { //链式前向星建图
int to, next, w;
} e[N];
int using_v[N], using_times[N]; //入队的点和点的入队次数
int head[N], dis[N];
int cnt = 0;
int n, m;
void add_edge(int u, int v, int w) {
e[cnt].to = v;
e[cnt].w = w;
e[cnt].next = head[u];
head[u] = cnt++;
}
int spfa(int start) {
queue<int> q;
dis[start] = 0; //起始点离自己的dis为0
using_v[start] = 1; //起始点标记
q.push(start); //入队
while (!q.empty()) {
int top = q.front(); //队首
q.pop(); //取出
using_v[top] = 0; //top这个点暂时没在队列中
for (int i = head[top]; i != -1; i = e[i].next) { //图遍历
if (dis[e[i].to] > dis[top] + e[i].w) { //松弛
dis[e[i].to] = dis[top] + e[i].w;
if (!using_v[e[i].to]) {
if (++using_times[top] > n) return 0; //存在负环
using_v[e[i].to] = 1;0
q.push(e[i].to);
}
}
}
}
return 1;
}
Floyd
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}
并查集
int father[maxn]; // 储存i的father父节点
void init() {
for (int i = 0; i < maxn; i++)
father[i] = i;
}
int find(int x) { // 迭代找根节点
int root = x; // 根节点
while (root != father[root]) { // 寻找根节点
root = father[root];
}
while (x != root) {
int tmp = father[x];
father[x] = root; // 根节点赋值
x = tmp;
}
return root;
}
void Union(int x, int y) { // 将x所在的集合和y所在的集合整合起来造成一个集合。
int a, b;
a = findRoot(x);
b = findRoot(y);
father[a] = b; // y连在x的根节点上 或father[b] = a为x连在y的根节点上;
}
最小生成树
Kruskal(稀疏图)
void Kruskal() {
ans = 0;
for (int i = 0; i < len; i++) {
if (find(edge[i].a) != find(edge[i].b)) {
Union(edge[i].a, edge[i].b);
ans += edge[i].len;
}
}
}
Prim(稠密图)
int head[N], cnt = 0,tot = 0;
int match[N],dis[N], vis[N];
int n,m;
struct edge
{
int to,next,w;
};
edge e[N<<1];
void add_edge(int a, int b, int w)
{
e[cnt].to = b;
e[cnt].next = head[a];
e[cnt].w = w;
head[a] = cnt++;
}
ll prim()
{
mem(dis,0x3f);
mem(vis,0);
dis[1] = 0;
ll sum = 0;
priority_queue< pii,vector<pii>,greater<pii> > pq;
pq.push({0,1});
while(pq.size() && tot < n)
{
int d = pq.top().first,u = pq.top().second;
pq.pop();
if(vis[u]) continue;
tot++;
sum += d;
vis[u] = 1;
for(int i = head[u]; i != -1; i = e[i].next)
{
int v = e[i].to;
if(e[i].w < dis[v])
{
dis[v] = e[i].w;
pq.push({dis[v],v});
}
}
}
return sum;
}
void solve()
{
cin >> n >> m;
mem(head,-1);
for(int i = 1; i <= m; i++)
{
int u,v,w;
cin >> u >> v >> w;
add_edge(u,v,w);
add_edge(v,u,w);
}
ll res = prim();
if(tot == n)cout << res << endl;
else cout << "orz" << endl;
}
二分图
二分图染色
int head[N], cnt = 0;
int color[N];
struct edge{
int to,next;
};
edge e[N<<1];
void add_edge(int a, int b)
{
e[cnt].to = b;
e[cnt].next = head[a];
head[a] = cnt++;
}
bool dfs(int u, int c)
{
color[u] = c;
for(int i = head[u]; i != -1; i = e[i].next)
{
int v = e[i].to;
if(!color[v])//i指向的点j未染色
{
if(!dfs(v, 3 - c)) return false;//1.j未染色&&染色失败
}
else if(color[v] == c) return false;//2.已经染色,但是颜色相同,矛盾
}
return true;//成功染色
}
void solve()
{
int n, m;
cin >> n >> m;
mem(head, -1);
while (m --)
{
int a, b;
cin >> a >> b;
add_edge(a, b), add_edge(b,a);//无向图
}
bool flag = true;
for(int i = 1; i <= n; i ++)
{
if(!color[i])//i未染色
{
if(!dfs(i, 1))//i染色失败,产生冲突
{
flag = false;
break;
}
}
}
if(flag) puts("Yes");
else puts("No");
}
二分图最大匹配(匈牙利算法)
int head[N], cnt = 0;
int match[N],vis[N];
struct edge{
int to,next;
};
edge e[N<<1];
void add_edge(int a, int b)
{
e[cnt].to = b;
e[cnt].next = head[a];
head[a] = cnt++;
}
bool dfs(int x)
{
for(int i = head[x]; i != -1; i = e[i].next)
{
int v = e[i].to;
if(!vis[v]) {
vis[v] = 1;
if(!match[v] || dfs(match[v])) {
match[v] = x;
return true;
}
}
}
return false;
}
void solve()
{
int n, m, e;
cin >> n >> m >> e;
mem(head, -1);
for(int i = 1;i <= e;i++) {
int u,v;
cin >> u >> v;
add_edge(u,v);
}
ll res = 0;
for(int i = 1;i <= n;i++) {
mem(vis,0);
if(dfs(i)) res++;
}
cout << res << endl;
}
网络流
最大流dinic
struct edge
{
int to, next, cap;
};
edge e[M << 1];
int n, m, head[N << 1], cnt = 0, d[N];
ll s, t, maxflow = 0, mincost = 0;
void add_edge(int u, int v, int cap)
{
e[cnt].to = v, e[cnt].next = head[u], head[u] = cnt, e[cnt++].cap = cap;
e[cnt].to = u, e[cnt].next = head[v], head[v] = cnt, e[cnt++].cap = 0;
}
bool bfs() //在残留网络上构建分层图
{
queue<int> q;
mem(d, -1);
q.push(s);
d[s] = 0;
while (q.size())
{
int u = q.front();
q.pop();
for (int i = head[u]; i != -1; i = e[i].next)
{
int v = e[i].to;
if (e[i].cap > 0 && d[v] == -1)
{
q.push(v);
d[v] = d[u]+1;
}
}
}
return (d[t]!=-1);
}
ll dinic(int u,int flow) //分层图上增广
{
if(u == t) return flow;
ll res = 0; // 当前增广路流量
for(int i = head[u]; i != -1; i = e[i].next)
{
int v = e[i].to;
if(e[i].cap > 0 && d[u] + 1 == d[v])
{
int tmp = dinic(v,min(flow,e[i].cap));
flow -= tmp; //更新正反向边
e[i].cap -= tmp;
res += tmp;
e[i ^ 1].cap += tmp;
if(flow == 0) break;
}
}
if(res == 0) d[u] = -1;
return res;
}
void solve()
{
cin >> n >> m >> s >> t;
maxflow = 0;
cnt = 0;
mem(head, -1);
for (int i = 1; i <= m; i++)
{
int u,v,f;
cin >> u >> v >> f;
add_edge(u, v, f);
}
while(bfs())
{
maxflow += dinic(s,inf);
}
cout << maxflow << endl;
}
最小费用最大流(spfa费用流)
struct edge
{
int to, next, cap, cos;
};
edge e[M << 1];
int n, m, a[N], head[N << 1], cnt = 0, dis[N], vis[N], flow[N], pre[N], last[N];
int s, t, maxflow = 0, mincost = 0;//s源点,v汇点
void add_edge(int u, int v, int cap, int cos)
{
e[cnt].to = v, e[cnt].next = head[u], head[u] = cnt, e[cnt].cap = cap, e[cnt++].cos = cos;
e[cnt].to = u, e[cnt].next = head[v], head[v] = cnt, e[cnt].cap = 0, e[cnt++].cos = -cos;
}
bool spfa()
{
queue<int> q;
mem(dis, 0x3f);
mem(vis, 0);
vis[s] = 1, dis[s] = 0, flow[s] = inf;
q.push(s);
while (q.size())
{
int u = q.front();
vis[u] = 0;
q.pop();
for (int i = head[u]; i != -1; i = e[i].next)
{
int v = e[i].to;
if (e[i].cap && dis[v] > dis[u] + e[i].cos)
{
dis[v] = dis[u] + e[i].cos;
flow[v] = min(flow[u], e[i].cap);
pre[v] = u;
last[v] = i;
if (!vis[v])
{
vis[v] = 1;
q.push(v);
}
}
}
}
if (dis[t] == 0x3f3f3f3f) return false;
else return true;
}
void MCMF()
{
while (spfa())
{
int now = t;
maxflow += flow[t];
mincost += flow[t] * dis[t];
while (now != s)
{
e[last[now]].cap -= flow[t];
e[last[now] ^ 1].cap += flow[t];
now = pre[now];
}
}
}
void solve()
{
cin >> n >> m >> s >> t;
maxflow = 0, mincost = 0;
cnt = 0;
mem(head, -1);
for (int i = 1; i <= m; i++)
{
int u,v,f,c;
cin >> u >> v >> f >> c;
add_edge(u, v, f, c);
}
MCMF();
cout << maxflow << " " << mincost << endl;
}