图论笔记

全部笔记提示

接下来整理的笔记,有一个很重要的是初始化,如果不初始化,运行以后题目可能不会输出。
这份笔记其实不是非常准确(因为无法在markdown上画图,且不能一步一步讲解),最好还是根据模板一起理解,因为我基本是在解释模板。
我在最后会把老师的讲义放在最后,请对号入座。

并查集笔记

算法解释

建边,由于挨个挨个查找比较麻烦所以要进行【路径压缩】,让每一个节点直接指向根节点。(之所以可以这么做,是因为题目只询问两点是否在同一集合)

代码解释

并查集类型的题主要由4个(包括初始化)函数构成:

  • init函数:初始化(最重要的一步,不添加会不输出)。
  • find函数:查找这个节点的根节点。
  • unite函数:建边,由于可能将两个图(更准确的来说是树)的根节点连到一起这时无论是哪一个节点(下称X)指向另一个节点(下称Y),根据【路径压缩】,指向Y的X其下的子节点会分别指向Y,所以我们要让节点最少的树的根节点指向节点更多的树的根节点。这样时间才会更快。(but,这个连接条件会因题目而异)。
    *same函数(因题而异):判断两点是否在一个集合内。

模板代码

P3367 【模板】并查集

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10; 
int n,m;
int fa[N],sz[N];
void init()
{
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;
		sz[i]=1;
	}
}
int find(int x)
{
	if(fa[x]!=x)
	{
		fa[x]=find(fa[x]);
	}
	return fa[x];
}
void unite(int x,int y)
{
	int fx=find(x);
	int fy=find(y);
	if(fx==fy) return ;
	if(sz[fx]<sz[fy])
	{
		swap(fx,fy);
	}
	fa[fy]=fx;
	sz[fx]+=sz[fy];
}
bool same(int x,int y)
{
	return find(x)==find(y);
}
int main()
{
	cin>>n>>m;
	init();
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		cin>>z>>x>>y;
		if(z==1)
		{
			unite(x,y);
		}
		else
		{
			if(same(x,y))
			{
				cout<<"Y"<<"\n";
			}
			else
			{
				cout<<"N"<<"\n";
			}
		 } 
	}
	return 0;
}

最小生成树(Kruskal)笔记

算法解释

运用并查集的思想,从小到大排序,若两点不在同一集合便将两点相连。

模板代码

P3366 【模板】最小生成树

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int n,m,s,t,fa[N],sz[N];
struct ll{
	int u,v,sum;
}a[N]; 
void init()
{
	for(int i=1;i<=n;i++)
	{
		fa[i]=i;
		sz[i]=1;
	}
} 
int find(int x)
{
	if(fa[x]!=x)
	{
		fa[x]=find(fa[x]);
	}
	return fa[x];
}
void unite(int x,int y)
{
	int fx=find(x),fy=find(y);
	if(fx==fy) return ;
	if(sz[fx]<sz[fy])
	{
		swap(fx,fy);
	}
	fa[fy]=fx;
	sz[fx]+=sz[fy];
}
bool same(int x,int y)
{
	return find(x)==find(y);
}
bool cmp(ll x,ll y)
{
	return x.sum<y.sum;
}
int main()
{
	int cnt=0,ans=-1;
	cin>>n>>m;
	init();
	for(int i=1;i<=m;i++)
	{
		cin>>a[i].u>>a[i].v>>a[i].sum;
	}
	sort(a+1,a+m+1,cmp);
	for(int i=1;i<=m;i++)
	{
		if(!same(a[i].u,a[i].v))
		{
			unite(a[i].u,a[i].v);
			cnt++;
			ans+=a[i].sum;	
			if(cnt==n-1)
			{
				cout<<ans+1;
				return 0;
			}
		}
	}
	cout<<"orz";
	return 0;
}

Floyd算法笔记

一些废话

个人认为最通俗易懂的图论算法,但由于有三重循环,所以不是什么很好用的算法。

算法解释

定义中转节点 K,若 i->k 能走并且 k->j 能走那么 i->j能走一定成立。当然若本身 i->j 的权值就小,那么就不会更新,也就是取最小值。

模板代码

【模板】Floyd

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int n,m,f[N][N];
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            f[i][j]=INT_MAX;
        }
        f[i][i]=0;
    }
    for(int i=1;i<=m;i++)
    {
        int u,v,w;
        cin>>u>>v>>w;
        f[u][v]=f[v][u]=min(w,f[u][v]);
    }
    
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                if(f[i][k]!=INT_MAX&&f[k][j]!=INT_MAX)
                f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cout<<f[i][j]<<" ";
        }
        cout<<"\n";
    }
    return 0;
}
/*当你做题很顺时

            ━━━∑(゚□゚*川)——
*/

传递闭包算法笔记

算法解释

完全基于Floyd算法,没什么好解释的。

模板代码

【模板】传递闭包

#include<bits/stdc++.h>
using namespace std;
const int M=3e3+10;
const int N=3e5+10;
int n,m,f[M][M];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>f[i][j];
		}
	}
	for(int k=1;k<=n;k++)
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(f[i][k]&&f[k][j])
				{
					f[i][j]=1;
				}
			}
		}
	}
	int ans=-1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cout<<f[i][j]<<" ";
		}
		cout<<"\n";
	}
    return 0;
}
/*当你做题很顺时

            ━━━∑(゚□゚*川)——
*/

Prim算法笔记 Dijkstra(下面简称D)算法笔记

前情提要

我为什么要把Prim划掉呢?(我还找了半天Prim是什么)因为它这个算法很鸡肋,凡是它能做出来的题D也能做,还比它做的好。因此在这里不对Prim进行介绍了。

算法提示

D算法不能处理负环。

算法解释

其实这种算法和bfs非常的像。(然后没了

模板代码

【模板】单源最短路径(弱化版)

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+10; 
int n,m,k,dist[N],tmp[N];
struct node
{
    int v;
    int w;
};
vector <node> a[N];
void D(int s)
{
    priority_queue<pair<int,int> ,vector<pair<int,int> > ,greater<pair<int,int> > >q;
    for(int i=1;i<=n;i++)
    {
        dist[i]=INT_MAX;
    }
    memset(tmp,0,sizeof(tmp));
    dist[s]=0;
    q.push({0,s});
    while(!q.empty())
    {
        pair<int,int> p=q.top();
        q.pop();
        int u=p.second;
        if(tmp[u]==1) continue;
        tmp[u]=1;
        for(auto it:a[u])
        {
            int v=it.v;
            int w=it.w;
            if(dist[v]>dist[u]+w)
            {
                dist[v]=dist[u]+w;
                q.push({dist[u]+w,v});
            }
        }
    }
}
int main()
{
	cin>>n>>m>>k;
    for(int i=1;i<=m;i++)
    {
        int v,u,w;
        cin>>u>>v>>w;
        a[u].push_back({v,w});
    }
    D(k);
	for (int i = 1; i <= n; i++) {
		cout << dist[i] << " ";
	}
    cout<<"\n";
	return 0;
}
/*当你做题很顺时

            ━━━∑(゚□゚*川)——
*/
posted @ 2026-02-17 14:37  teto_cai  阅读(8)  评论(0)    收藏  举报