c++专题七

c++专题七(图论)

存图

1.邻接表
vector<int> g[N];		//带边:vector<pair<int,int>> g[N];
void add(int x,int y){
	g[x].push_back(y);
}
//或者:
for(int y:g[x]){

}

最短路

1.Floyd

(边多用Floyd)

思路:

枚举中转点k,检查由x点经过此点到y点的路径是否比原先优。更新由x点到y点的最短距离。

初始化:

  1. 没连接的距离为正无穷(0x3f3f3f3f)

  2. 自己到自己距离为0

  3. dis[i][j]为距离,双向需要dis[i][j]dis[j][i]都赋值

void Floyd() {
	for (int k = 1;k <= n;++k) {
		for (int i = 1;i <= n;++i) {
			for (int j = 1;j <= n;++j) {
				f[i][j] = min(f[i][j],f[i][k] + f[k][j]);
			}
		}
	}
}

2.Dijkstra

(只能处理正权边,边少用n次Dijkstra)

思路:

  1. 先将点划为两堆,起初第一堆只有起点S一个点。

  2. 每次从第二堆里距离 点最近的点(这就是贪心了)取出,放入第一堆中,并更新最短路,直到第

    二堆中没有节点为止。

  3. 此时维护出的dist[i]就是S到i点的最短距离

代码:

int n,m,s,dis[N];
bool vis[N];
struct node{
	int pos,dis;
	friend bool operator<(const node &a,const node &b){
		return a.dis>b.dis;
	}
};

priority_queue<node> q;
void dijkstra(int s){
	memset(dis,0x3f,sizeof dis);
	memset(vis,0,sizeof vis);
	q.push((node){s,dis[s]=0});
	while(!q.empty()){
	node p=q.top();
	q.pop();
	int x=p.pos;
	if(vis[x])continue;
	vis[x]=1;
	for(auto e:g[x]){
	
	}
	}
}

无根数

一个没有固定根结点的树称为 无根树

(有n个结点,n-1条边的连通无向图,无向无环的连通图,任意两点之间有且只有一条简单的无向图)

有根树

在无根树的基础上,指定一个结点称为 ,则形成一棵 有根树

二叉树

每个结点最多只有两个儿子(子结点)的有根树称为二叉

树。常常对两个子结点的顺序加以区分,分别称之为左子结点和右子结点。

大多数情况下,二叉树 一词均指有根二叉树。

存储及遍历(用邻接表

void dfs(int x,int fa) {
	for (auto y : G[x]) {
		if (y == fa) continue;
		dfs(y,x);
	}
}
调用:dfs(root,0);

或bfs:

queue <int> q;
void bfs(int root) {
	q.push(root);
	while (!q.empty()) {
		int x = q.front();q.pop();
		//do something
	}
}
调用:bfs(root)

树形dp

例:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <string>
#include <queue>
#include <map>
/* #include <unordered_map> */
#include <bitset>
#include <vector>
void fre() { system("clear"), freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); }
void Fre() { system("clear"), freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair<int, int>
#define m_p make_pair
#define INF 0x3f3f3f3f
#define esp 1e-7
#define for_(i, s, e) for(int i = (ll)(s); i <= (ll)(e); i ++)
#define rep_(i, e, s) for(int i = (ll)(e); i >= (ll)(s); i --)
#define sc scanf
#define pr printf
#define sd(a) scanf("%d", &a)
#define ss(a) scanf("%s", a)
#define size() size() * 1LL
#define mod (ll)(998244353)
#define Min(a, b, c) min(a, min(b, c))
using namespace std;

const int mxn = 105;
int dp[mxn][mxn];
vector<int> e[mxn];
int w[mxn][mxn];
int n, m;

void dfs(int u, int p)
{
    if(! e[u].size()) return;
    for_(i, 0, e[u].size() - 1)
    {
        int v = e[u][i];
        if(v == p) continue;
        dfs(v, u);

        //这里的两重for循环dp枚举思路就像 01背包的动态规划,我们当前在节点u,如果我们给子节点v(把u的任意一个子节点v,在不同空间下可以看作不同的物品)分配b条边,在背包总空间为a的基础上,又因为边u-v 也占用一条边(一个空间),所以剩下的边数(空间)为 a - b - 1,
        rep_(a, m, 1)               //从大到小枚举,当前可以分配的总的边数(其实就像 从大到下枚举背包的空间,防止重复购买某个物品) 
            for_(b, 0, a - 1)
                dp[u][a] = max(dp[u][a], dp[v][b] + dp[u][a - b - 1] + w[u][v]);
    }
}


int main()
{
    /* fre(); */
    sc("%d %d", &n, &m);
    int u, v, x;
    for_(i, 2, n)
    {
        sc("%d %d %d", &u, &v, &x);
        e[u].pb(v);
        e[v].pb(u);
        w[u][v] = x;
        w[v][u] = x;
    }

    dfs(1, 0);
    pr("%d\n", dp[1][m]);

    return 0;
}

posted @   佘雅晴  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示