ACM图论板子

头文件

#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;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值