【洛谷】最小生成树题目笔记


题目链接

P1536 村村通
P1547 Out of Hay
P2820 局域网
P1546 最短网络 Agri-Net
P2330 繁忙的都市


一、村村通

裸的最小生成树……
一道水的不能再水的题……
先贴上代码

#include
using namespace std;
int n,m,f[2000020],ans=0;
struct pvp{int t1,t2;}e[2000020];
int getf(int k){if(f[k]==k){return k;}else{return getf(f[k]);}}
void merge(int x,int y){f[getf(x)]=getf(y);}
bool cmp(pvp a,pvp b){return a.t1>e[i].t1>>e[i].t2;merge(e[i].t1,e[i].t2);}//输入哪两个城镇之间有路,然后就把两个城镇之间搞出关系来……
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=n;i++){if(getf(i)==i) ans++;}
        //并查集的基本模型for,因为现在每个城镇的数值和自己的编号已经发生改变,所以,判断有多少个没有变化的,就有多少种关系。当然,最后ans的值要清空。
        cout<

太乱了?看不懂?我也是这样。为了压行……等会就看懂了
首先,最小生成树有两种经典的求法:Kruskal算法,Prim算法
这里用的是Kruskal算法,Kruskal算法用来求稀疏图,Prim算法用来求稠密图
Kruskal算法核心为并查集

  • struct结构体用来存边,t1-t2表示t1与t2相连,如果有权值可加上t3
  • getf函数(又称为find函数)用来把两者变为有关系,如果两者已经有关系或者相同,就返回出关系,如果还没有关系,就一直一直递归下去………
  • merge函数,有没有都无所谓,看起来好看点罢了,其实可以直接用f[getf(e[i].x)]=getf(e[i].y)代替merge(e[i].t1,e[i].t2);},只不过为了好看点。。。
    merge函数目的是合并两者,也就是强迫两者有关系。。。
  • cmp结构体排序函数,其实有没有无所谓(在这道题里),就是让sort排序按照自己想要排序的方法去排序

Out of Hay

也是一道裸题,只不过要求的东西不一样

#include
#include
using namespace std;
struct edge{int t1,t2,t3;}e[200001];
int n,m,maxn=0,f[200001],et1,et2,num=0;
bool cmp(edge a,edge b){return a.t3>n>>m;
	for(int i=1;i<=n;i++) f[i]=i;
	for(int i=1;i<=m;i++) cin>>e[i].t1>>e[i].t2>>e[i].t3;
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=m;i++)
	{
		if(getf(e[i].t1)==getf(e[i].t2)) continue;                //判断,如果两者已经有了关系,那么不再用两者相连的边,直接continue
		maxn=max(maxn,e[i].t3);                                   //不然,如果这条边比原来的maxn还要大,就记录
		f[getf(e[i].t2)]=getf(e[i].t1);                           //和merge函数一个道理,因为选用了这条边,所以强制他们有关系
		if(++num==n-1) break;                                     //如果已经选用了n-1条边,那么符合最小生成树的性质,就不在继续往下选边   
	}
	cout<

局域网

#include
#include
using namespace std;
struct edge{int t1,t2,t3;}e[200001];
bool cmp(edge a,edge b){return a.t3>n>>m;
	for(int i=1;i<=n;i++) f[i]=i;
	for(int i=1;i<=m;i++){cin>>e[i].t1>>e[i].t2>>e[i].t3;k+=e[i].t3;}   //k累加的目的是求出所有等到后面求最终答案时更加方便
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=m;i++)
	{
		et1=getf(e[i].t1);
		et2=getf(e[i].t2);
		if(et1==et2) continue;
		sum+=e[i].t3;                                                  //如果符合,那么sum累加,其实还有种更简便的做法,就是如果不符合就sum累加,这样不用用到k,也能算出最终答案
		f[et2]=et1;
		if(++ans==n-1) break;
	}
	cout<

你可能感兴趣的:(图论)