一些容易忘记的算法整理

对拍找错

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int tt = 1;
	cin >> tt;
	for(int i = 1; i <= tt; i ++){
		cout << "Case : " << i << ' ';
		system("rand.exe > try.txt");//rand生成数据,try是存放数据文件
		system("accode.exe < try.txt > yh.txt");//代码1运行
		system("wacode.exe < try.txt > bl.txt");//代码2运行
		if(!(system("fc yh.txt bl.txt"))) //输出比较
		cout << "yes" << endl;
		else break;
	}
	return 0;
}


交互题

交互题用`fflush(stdout);`刷新缓冲区

KMP

for(int i = 2, j = 0; i <= ns; i ++)//ns为s串长度
	{
		while(j && s[i] != s[j + 1])
			j = nex[j];
		if(s[i] == s[j + 1])
		j ++;
		nex[i] = j;
	}
	int num = 0;
	for(int i = 1, j = 0; i <= nt; i ++)//nt为t串长度
	{
		while(j && t[i] != s[j + 1])
			j = nex[j];
		if(t[i] == s[j + 1])
			j ++;
		if(j == ns)//匹配成功
		{
			num ++;//num的值为s串在t中出现次数
			j = nex[j];
		}
	}

高斯消元-解线性方程组

#include <iostream>
using namespace std;
const int N = 15;
double a[N][N], b[N][N];
int n;
void gauss()
{
    // 转化为上三角矩阵
    for(int i = 1; i <= n; i ++)//i表示处理第i列
    {
        int t = i;//找到最优的某一行来处理这一列
        for(int j = i + 1; j <= n; j ++)
            if(abs(b[j][i]) > abs(b[t][i]))
                t = j;
        // 交换
        for(int j = i; j <= n + 1; j ++)//把第t行交换到第i行
            swap(b[t][j], b[i][j]);
        
        for(int j = n + 1; j >= i; j --)//把第i行同时除以第i行第i列的值
            b[i][j] = b[i][j] / b[i][i];
        // 消元
        for(int j = i + 1; j <= n; j ++)
            for(int k = n + 1; k >= i; k --)
                b[j][k] = b[j][k] - b[i][k] * b[j][i];
    }
    // 转化成对角矩阵
    for(int i = n; i > 1; i --)
        for(int j = i - 1; j >= 1; j --)
        {
            b[j][n + 1] = b[j][n + 1] - b[j][i] * b[i][n + 1];
            b[j][i] = 0;
        }
}
int main()
{
    cin >> n;
    // 输入n + 1个n维方程
    for(int i = 0; i <= n; i ++)
        for(int j = 1; j <= n; j ++)
            cin >> a[i][j];
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= n; j ++)
        {
            b[i][j] = 2 * (a[i][j] - a[0][j]);
            b[i][n + 1] += a[i][j] * a[i][j] - a[0][j] * a[0][j];
        }
    gauss();
    for(int i = 1; i <= n; i ++)
    printf("%.3lf ", b[i][n + 1]);
}

组合数

在这里插入图片描述
在这里插入图片描述![在这里插入图片描述](https://img-blog.csdnimg.cn/103b2576a1e9475ea711304d7d1be653.png

![在这里插入图片描述](https://img-blog.csdnimg.cn/439106c7df2f49e3971e20d28f537791.png在这里插入图片描述在这里插入图片描述
一些组合数公式


欧拉定理

在这里插入图片描述


扩展欧拉定理

在这里插入图片描述


分解质因数欧拉函数

在这里插入图片描述代码

int getoula(int n)
{
	int res = 1;
	for(int i = 2; i * i <= n; i ++)
	{
		if(n % i == 0)
		{
			int t = 1;
			while(n % i == 0){
				n /= i;
				t = t * i;
			}
			t = t / i;
			res = res * t * (i - 1);
		}
	}
	if(n > 1)
	res = res * (n - 1);
	return res;
}

筛法求欧拉函数

int prime[N], st[N], cnt, oula[N];
void getoula(int n)
{
    oula[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        if(!st[i])
        {
            prime[cnt++] = i;
            oula[i] = i - 1;
        }
        for(int j = 0; prime[j] * i <= n; j ++)
        {
            st[prime[j] * i] = 1;
            if(i%prime[j] == 0)
            {
                oula[prime[j] * i] = oula[i] * prime[j];
                break;
            }
            oula[prime[j] * i] = oula[i] * (prime[j] - 1);
        }
    }
}

欧拉图、欧拉回路、欧拉路径(通路)

![在这里插入图片描述](https://img-blog.csdnimg.cn/b1f3a79227194044a722cf1205d0a7e4.png

在这里插入图片描述


tarjan缩点

void tarjan(int x)
{
    dfn[x] = low[x] = ++timetamp;
    q.push(x); st[x] = 1;
    for(int i = h[x]; i != -1; i = ne[i])
    {
        if(!dfn[e[i]])
        {
            tarjan(e[i]);
            low[x] = min(low[x], low[e[i]]);
        }
        else if(st[e[i]] == 1)
            low[x] = min(low[x], dfn[e[i]]);
    }
    if(dfn[x] == low[x])//缩成一个点
    {
        ++ cnt;
        while(q.top() != x)
        {
            id[q.top()] = cnt;//id数组为每个点缩点后在哪个点内
            st[q.top()] = 0;
            q.pop();
            num[cnt] ++;//num为缩后的点由几个原来的点组成
        }
        id[q.top()] = cnt;
        st[q.top()] = 0;
        q.pop();
        num[cnt] ++;
    }
}
int main()
{
    cin >> n >> m;
    int a, b, res = 0;
    memset(h, -1, sizeof h);
    for(int i = 0; i < m; i ++)
    {
        cin >> a >> b;
        add(a, b);
    }
    for(int i = 1; i <= n; i ++)
    if(!dfn[i])
    tarjan(i);
    //缩完点后用新生成的点建边即可建成新的拓扑图
    for(int i = 1; i <= n; i ++)
    {
        for(int j = h1[i]; j != -1; j = ne[j])
        {
            if(id[i] != id[e[j]])
            {
                addid(id[i], id[e[j]]);
            }
        }
    }
}

最少的需要新建多少道路,使每两点之间都会至少有两条相互分离的路径,两条路径相互分离,是指两条路径没有一条重合的道路。

#include <iostream>
#include <stack>
#include <cstring>
using namespace std;
const int N = 5020, M = 20020;
int h[N], e[M], ne[M], idx;
int id[N], cnt, d[N];
int dfn[N], low[N], timetamp;
stack<int> q;
void add(int x, int y)
{
    e[idx] = y; ne[idx] = h[x]; h[x] = idx ++;
}
void tarjan(int x, int f)
{
    dfn[x] = low[x] = ++ timetamp;
    q.push(x);
    for(int i = h[x]; i != -1; i = ne[i])
    {
        if(!dfn[e[i]])
        {
            tarjan(e[i], i);
            low[x] = min(low[x], low[e[i]]);
        }
        else if (i != (f ^ 1))
        low[x] = min(low[x], dfn[e[i]]);
    }
    if(dfn[x] == low[x])
    {
        int y;
        ++ cnt;
        do{
            y = q.top();
            q.pop();
            id[y] = cnt;
        }while(y != x);
    }
}
int main()
{
    int n, m, a, b;
    cin >> n >> m;
    memset(h, -1, sizeof h);
    for(int i = 0; i < m; i ++)
    {
        cin >> a >> b;
        add(a, b); add(b, a);
    }
    tarjan(1, -1);
    for(int i = 1; i <= n; i ++)
    {
        for(int j = h[i]; j != -1; j = ne[j])
        {
            if(id[i] != id[e[j]])
            {
                d[id[i]] ++;
            }
        }
    }
    int ans = 0;
    for(int i = 1; i <= cnt; i ++)
    {
        if(d[i] == 1)
        ans ++;
    }
    cout << (ans + 1) / 2;
}

给定一个由 n 个点 m 条边构成的无向图,请你求出该图删除一个点之后,连通块最多有多少。

#include <iostream>
#include <cstring>
using namespace std;
const int N = 10020, M = 30020;
int h[N], e[M], ne[M], idx, ans, sum;
int dfn[N], low[N], timetamp, root;
void add(int x, int y)
{
    e[idx] = y; ne[idx] = h[x]; h[x] = idx ++;
}
void tarjan(int x, int f)
{
    int cnt = 0;
    dfn[x] = low[x] = ++ timetamp;
    for(int i = h[x]; i != -1; i = ne[i])
    {
        // if((1 ^ f) == i)
        // continue;
        if(!dfn[e[i]])
        {
            tarjan(e[i], i);
            low[x] = min(low[x], low[e[i]]);
            if(low[e[i]] >= dfn[x])
            cnt ++;
        }
        else
        low[x] = min(low[x], dfn[e[i]]);
    }
    if(x != root && cnt)
    cnt ++;
    ans = max(ans, cnt);      
}
int main()
{
    int n, m;
    while(cin >> n >> m, n)
    {
        memset(h, -1, sizeof h);
        memset(dfn, 0, sizeof dfn);
        idx = timetamp = sum = ans = 0;
        int a, b;
        for(int i = 0; i < m; i ++)
        {
            cin >> a >> b;
            add(a, b); add(b, a);
        }
        for(int i = 0; i < n; i ++)
        {
            if(!dfn[i])
            {
                root = i;
                tarjan(i, -1);
                sum ++;
            }
        }
        cout << sum + ans - 1 << endl;
    }
}

扩展欧几里得

#include <iostream>
#define int long long
using namespace std;
void exgcd(int a, int b, int &x, int &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return;
    }
    exgcd(b, a % b, x, y);
    swap(x, y);
    y = y - x * (a / b);
}
signed main()
{
    int a, b, x, y;
    cin >> a >> b;
    exgcd(a, b, x, y);
    cout << (x % b + b) % b;
}

代码功能是求出最小的正整数x使存在y满足 ax + by = 1.

#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
int d;
int exgcd(int a, int b, int &x, int &y)
{
    if(b == 0)
    {
        if(a == 0 || d % a != 0)
        return true;
        x = d / a;
        y = 0;
        return false;
    }
    if(exgcd(b, a % b, x, y))
    return true;
    swap(x, y);
    y = y - x * (a / b);
    return false;
}
signed main()
{
	int a, b, x, y, m;
	m = b / __gcd(a, b);
    exgcd(a, b, x, y);
    if(!f)
    cout << (x % m + m) % m;
}

改进后能求出最小的正整数x使存在y满足 ax + by = d.


求逆元

逆元可以看作模运算中的倒数,假设 a 模 P 的逆元为 x,则 ax % P = 1(等价于 ax ≡ 1 (% P) ),
x ≡ (1 / a)(% P),因此(b / a) % P = (b * (1 / a)) % P = (b * x) % P;
1、当 a % P 中的 P 为质数时可以用 费马小定理 求 a 模 P 的逆元,逆元为 a 的 P - 2 次方;
2、如果 P 不是素数,且 a 与 P 互质,则需要用 扩展欧几里得 算法求逆元,调用扩展欧几里得的 exgcd(a, P, x, y); 函数,可以求出满足条件的 x 和 y 使 ax + Py = 1,其中 x 就是 a 模 P 的逆元;
3、如果 a 与 P 不互质则逆元不存在。


中国剩余定理

求x的值为多少,使下面的同余方程都成立
在这里插入图片描述x即为这一组同余方程的解,假设 g 为m1,m2,…,mn 的最小公倍数,x + kg(k ∈ Z)则为这组同余方程的所有解


LCA

int h[N], e[N * 2], ne[N * 2], idx, l[N][20], st[N], depth[N];
void add(int x, int y)
{
    e[idx] = y; ne[idx] = h[x]; h[x] = idx ++;
}
void dfs(int r)
{
    queue<int> q;
    q.push(r);
    st[r] = 1;
    depth[r] = 1;
    while(!q.empty())
    {
        int x = q.front();
        q.pop();
        for(int i = h[x]; i != -1; i = ne[i])
        if(!st[e[i]])
        {
            q.push(e[i]);
            depth[e[i]] = depth[x] + 1;
            st[e[i]] = 1;
            l[e[i]][0] = x;
            for(int j = 1; j < 20; j ++)
            l[e[i]][j] = l[l[e[i]][j - 1]][j - 1];
        }
    }
}
int lca(int x, int y)
{
    if(depth[x] < depth[y])
    swap(x, y);
    for(int i = 19; i >= 0; i --)
    if(depth[l[x][i]] >= depth[y])
    x = l[x][i];
    if(x == y)
    return x;
    for(int i = 19; i >= 0; i --)
    {
        if(l[x][i] != l[y][i])
        {
            x = l[x][i]; y = l[y][i];
        }
    }
    return l[x][0];
}

中国剩余定理

在这里插入图片描述


网络流

求最大流,且图的最小割在数值上等于最大流

最大流:给出一个包含 n 个点和 m 条边的有向图(称其为网络),该网络上所有点分别编号为 1∼n,所有边分别编号为 1∼m,其中该网络的源点为 s,汇点为 t,网络上的每条边 (u,v) 都有一个流量限制 c(u,v),你需要给每条边 (u,v) 确定一个流量 f(u,v),要求除了源点和汇点外,其他各点流入的流量和流出的流量相等,源点流出的流量等于汇点流入的流量,最大流的值即为源点单位时间流出或汇点流入的流量.

Edmonds-Karp算法,复杂度nm^2, n表示点数,m表示边数,默认添加无向边,下面还有两个优化后的最大流算法

#include <iostream>
#include <cstring>
#include <queue>
#define int long long
using namespace std;
const int N = 10000, S = 1e15;
int h[N], ne[N], e[N], w[N], idx;
int s, t, ans = 0;
int st[N], pre[N], dist[N];
void add(int x, int y, int z)
{
	e[idx] = y;
	ne[idx] = h[x];
	w[idx] = z;
	h[x] = idx ++;
}
void flow(int x, int f)
{
	if(pre[x] != -1)
	{
		w[pre[x] ^ 1] -= f;
		w[pre[x]] += f;
		flow(e[pre[x]], f);
	}
	else
		ans = ans + f;
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int n, m, a, b, c, x;
	cin >> n >> m >> s >> t;
	memset(h, -1, sizeof h);
	while(m --){
		cin >> a >> b >> c;
		add(a, b, c);
		add(b, a, 0);
	}
	while(1){
		queue<int> q;
		q.push(s);
		dist[s] = S;
		for(int i = 1; i <= n; i ++)
			pre[i] = -1;
		while(!q.empty()){
			x = q.front();
			q.pop();
			for(int i = h[x]; i != -1; i = ne[i])
			{
				if(e[i] != s && pre[e[i]] == -1 && w[i] > 0)
				{
					pre[e[i]] = i ^ 1;
					dist[e[i]] = min(dist[x], w[i]);
					q.push(e[i]);
				}
			}
			if(pre[t] != -1)
				break;
		}
		if(pre[t] != -1)
			flow(t, dist[t]);
		else
			break;
	}
	cout << ans << '\n';
}

Dinic算法,优化后的最大流算法,复杂度为n^2m,同样加无向边,下面还有再次优化的Dinic算法

#include <iostream>
#include <cstring>
#include <queue>
#define int long long
using namespace std;
const int N = 10000, S = 1e15;
int h[N], ne[N], e[N], w[N], idx;
int n, s, t, ans = 0;
int dist[N], deep[N];
void add(int x, int y, int z)
{
	e[idx] = y;
	ne[idx] = h[x];
	w[idx] = z;
	h[x] = idx ++;
}
int dfs(int u, int s)
{
	if(u == t)
	return s;
	int x;
	for(int i = h[u]; i != -1; i = ne[i])
	{
		if(deep[e[i]] == deep[u] + 1 && w[i] != 0)
		{
			x = dfs(e[i], min(s, w[i]));
			if(x)
			{
				w[i] -= x;
				w[i ^ 1] += x;
				return x;
			}
			else
				deep[e[i]] = -1;
		}
	}
	return 0;
}
int bfs()
{
	queue<int> q;
	int x;
	q.push(s);
	for(int i = 1; i <= n; i ++)
	{
		deep[i] = -1;
	}
	deep[s] = 1;
	while(!q.empty()){
		x = q.front();
		q.pop();
		for(int i = h[x]; i != -1; i = ne[i])
		{
			if(deep[e[i]] == -1 && w[i] > 0)
			{
				deep[e[i]] = deep[x] + 1;
				q.push(e[i]);
				if(e[i] == t)
					return 1;
			}
		}
	}
	if(deep[t] == -1)
		return 0;
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int m, a, b, c, x;
	cin >> n >> m >> s >> t;
	memset(h, -1, sizeof h);
	while(m --){
		cin >> a >> b >> c;
		add(a, b, c);
		add(b, a, 0);
	}
	while(bfs()){
		while(x = dfs(s, S)){
			ans += x;
		}
	}
	cout << ans << '\n';
}

下面是head数组优化的Dinic算法,改动了两处
1、在dfs循环中定义循环变量 i 时加了 & 符号
2、在bfs初始化中将 head[i] 初始化为 h[i]

#include <iostream>
#include <cstring>
#include <queue>
#define int long long
using namespace std;
const int N = 10000, S = 1e15;
int h[N], ne[N], e[N], w[N], idx, head[N];
int n, s, t, ans = 0;
int dist[N], deep[N];
void add(int x, int y, int z)
{
	e[idx] = y;
	ne[idx] = h[x];
	w[idx] = z;
	h[x] = idx ++;
}
int dfs(int u, int s)
{
	if(u == t)
	return s;
	int x;
	for(int& i = head[u]; i != -1; i = ne[i])//此处多了&符号,也可此处不加&符号而在下面加代码head[u] = i;
	{
		if(deep[e[i]] == deep[u] + 1 && w[i] != 0)
		{
			x = dfs(e[i], min(s, w[i]));
			if(x)
			{
				w[i] -= x;
				w[i ^ 1] += x;
				return x;
			}
			else
				deep[e[i]] = -1;
		}
	}
	return 0;
}
int bfs()
{
	queue<int> q;
	int x;
	q.push(s);
	for(int i = 1; i <= n; i ++)
	{
		deep[i] = -1;
		head[i] = h[i];
	}
	deep[s] = 1;
	while(!q.empty()){
		x = q.front();
		q.pop();
		for(int i = h[x]; i != -1; i = ne[i])
		{
			if(deep[e[i]] == -1 && w[i] > 0)
			{
				deep[e[i]] = deep[x] + 1;
				q.push(e[i]);
				if(e[i] == t)
					return 1;
			}
		}
	}
	if(deep[t] == -1)
		return 0;
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int m, a, b, c, x;
	cin >> n >> m >> s >> t;
	memset(h, -1, sizeof h);
	while(m --){
		cin >> a >> b >> c;
		add(a, b, c);
		add(b, a, 0);
	}
	while(bfs()){
		while(x = dfs(s, S)){
			ans += x;
		}
	}
	cout << ans << '\n';
}

费用流
添加条件,网络上每条边都要花费,要求在保证最大流最大的情况下花费最小,这里每条边的花费是按这条边用到的容量在计算的
直接spfa求解,会比Dijkstra慢,下面有Dijkstra代码

#include <iostream>
#include <cstring>
#include <queue>
#define int long long
using namespace std;
const int N = 100000, S = 1e15;
int h[N], ne[N], e[N], w[N], f[N], idx, head[N];
int n, s, t, ans, sum;
int dist[N], cost[N], pre[N], st[N];//dist数组存的是从起点到当前点的最大流量,cost数组存的是起点到当前点每单位容量的花费,st数组用来执行spfa
void add(int x, int y, int z, int c)
{
	e[idx] = y;
	ne[idx] = h[x];
	w[idx] = z;
	f[idx] = c;
	h[x] = idx ++;
}
int spfa()
{
	for(int i = 1; i <= n; i ++)
	{
		st[i] = 0;
		pre[i] = -1;
		cost[i] = 1e15;
	}
	queue<int> q;
	q.push(s);
	st[s] = 1;
	dist[s] = S;
	cost[s] = 0;
	int x;
	while(!q.empty()){
		x = q.front();
		q.pop();
		st[x] = 0;
		for(int i = h[x]; i != -1; i = ne[i])
		{
			if(w[i] > 0 && cost[x] + f[i] < cost[e[i]])//这里比较的是单位容量的花费
			{
				dist[e[i]] = min(dist[x], w[i]);
				cost[e[i]] = cost[x] + f[i];
				pre[e[i]] = i ^ 1;
				if(!st[e[i]])
				{
					q.push(e[i]);
					st[e[i]] = 1;
				}
			}
		}
	}
	return pre[t] != -1;
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int m, a, b, c, x;
	cin >> n >> m >> s >> t;
	memset(h, -1, sizeof h);
	while(m --){
		cin >> a >> b >> c >> x;//输入有向边的起点、终点,最大容量和单位容量的花费
		add(a, b, c, x);
		add(b, a, 0, -1 * x);
	}
	while(spfa()){
		ans += dist[t];
		sum += dist[t] * cost[t];
		x = t;
		while(x != s){
			w[pre[x]] += dist[t];
			w[pre[x] ^ 1] -= dist[t];
			x = e[pre[x]];
		}
	}
	cout << ans << ' ' << sum << '\n';
}

原始对偶算法
这个算法没学,只把板子粘了过来
因为有负边所以不能用单纯的Dijkstra,要使用 Dijkstra 并优化复杂度需要保证没有负权环,要想办法把每条边的边权变为非负数,原始对偶算法就是这样一个方法,它给每个点增加了一个“势能”,利用势能和边权来把边权全部变为非负数

#include<bits/stdc++.h>
using namespace std;
const int N=5e3+5,M=1e5+5,INF=2e9;
int n,m,s,t;
int maxflow=0,mincost=0;
int head[N],fr[M],nxt[M],to[M],cnt=1;
int cap[M],w[M],fl[M],v[M],h[N]/*势能*/,dis[N];
int pre[N];
bool vis[N];
inline void create(int ff,int tt,int cc,int ww){nxt[++cnt]=head[ff],fr[cnt]=ff,head[ff]=cnt,to[cnt]=tt,cap[cnt]=cc,w[cnt]=ww;}
void spfa()//SPFA算初始势能
{
    static queue<int>q;
    for(int i=1;i<=n;++i)h[i]=INF;
    h[s]=0,vis[s]=1;
    q.push(s);
    int tmp;
    while(q.size())
    {
        tmp=q.front();
        q.pop();
        vis[tmp]=0;
        for(int i=head[tmp];i;i=nxt[i])
        {
            if(cap[i]&&h[to[i]]>h[tmp]+w[i])
            {
                h[to[i]]=h[tmp]+w[i];
                if(!vis[to[i]]) vis[to[i]]=1,q.push(to[i]);
            }
        }
    }
}
bool dij()//找增广路
{
    typedef pair<int,int> pii;
    static priority_queue<pii,vector<pii>,greater<pii>>q;
    for(int i=1;i<=n;++i)dis[i]=INF,vis[i]=0;
    dis[s]=0;
    q.push(make_pair(0,s));
    int tmp;
    while(!q.empty())
    {
        tmp=q.top().second;
        q.pop();
        if(vis[tmp])continue;
        vis[tmp]=1;
        for(int i=head[tmp],neww;i;i=nxt[i])
        {
            neww=w[i]+h[tmp]-h[to[i]];//更新边权
            if(cap[i]>fl[i]&&dis[to[i]]>dis[tmp]+neww)
            {
                dis[to[i]]=dis[tmp]+neww;
                pre[to[i]]=i;
                if(!vis[to[i]])q.push(make_pair(dis[to[i]],to[i]));
            }
        }
    }
    return dis[t]!=INF;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n>>m>>s>>t;
    for(int i=1,t1,t2,t3,t4;i<=m;++i)cin>>t1>>t2>>t3>>t4,create(t1,t2,t3,t4),create(t2,t1,0,-t4);
    spfa();
    while(dij())
    {
        int flow=INF;
        for(int i=t;i!=s;i=fr[pre[i]])flow=min(flow,cap[pre[i]]-fl[pre[i]]);//回溯
        for(int i=t;i!=s;i=fr[pre[i]])
        {
            fl[pre[i]]+=flow;
            fl[pre[i]^1]-=flow;
        }
        maxflow+=flow;
        mincost+=flow*(h[t]+dis[t]);
        for(int i=1;i<=n;++i)h[i]+=dis[i];
    }
    cout<<maxflow<<' '<<mincost;
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值