图的存储方式+并查集拓扑排序模板

目录

图的常用存储方式

1.邻接矩阵

2.邻接表

3.链式前向星

4.Vector存储(我最喜欢用的)

并查集

1.并查集模板

2.并查集例题

拓扑排序

1.拓扑排序模板

2.拓扑排序例题


图的常用存储方式

详:图的几种存储方式_roadkiller.的博客-CSDN博客_图的存储方式     

1.邻接矩阵

int map[maxn][maxn];
map[i][j]=w	//表示第i个顶点到第j个顶点有权值为w的边

2.邻接表

struct edgeNode
{
	int adjvex;//点
	int w;	   //权值
	struct edgeNode* next;//指向下一条边
};

struct edge
{
	int start;//起点
	int to;   //终点
	int cost; //权值
};

3.链式前向星

struct edge
{
	int to;   //当前边的终点
	int w ;   //权值 
	int next  //下一条边的下标   
};

4.Vector存储(我最喜欢用的)

vectoredge[maxn];
//edge[n][i-1]表示第n个节点第i条边连接的顶点
//edge[n].size()表示与第n个节点相连的顶点数(边数)

并查集

1.并查集模板

void init()            //初始化
{
	for (int i = 1; i <= n; i++)
		fa[i] = i;
}

int find(int x)        //查找
{
	if (fa[x] == x)
		return x;
	else
	{
		fa[x] = find(fa[x]);
		return fa[x];
        //=return fa[x]=find(fa[x])
        //路径压缩
	}
}

void unions(int x,int y)//合并
{
	int fa_x = find(x);
	int fa_y = find(y);
	fa[fa_x] = fa_y;
}

2.并查集例题

口袋的天空(洛谷P1195)

题目描述:有n片云和m条云之间的关系,求连成k个棉花糖所需的最小代价

输入:第一行三个数 n,m,k  接下来 m 行每行三个数 x,y,l  表示 x 云和 y 云可以通过 l 的代价连接

输出:最小代价,若不能则"No Answer"

分析:利用并查集,先对按权值对边节点排序,连接1棵树需要n-1条边,连接k棵数需要n-k条边

#include
#include
#include

using namespace std;

int n, m, k;
int x, y, l;

struct Node
{
	int x, y, l;
}node[10010];

bool cmp(Node& a, Node& b)
{
	return a.l < b.l;
}

int fa[1005];

void init()
{
	for (int i = 1; i <= n; i++)
		fa[i] = i;
}

int find(int x)
{
	if (fa[x] == x)
		return x;
	else
		return fa[x]=find(fa[x]);
}

void unions(int x, int y)
{
	int fa_x = find(x);
	int fa_y = find(y);
	fa[fa_x] = fa_y;
}

int ans = 0;
int sum;

int main()
{
	cin >> n >> m >> k;

	for (int i = 1; i <= m; i++)
	{
		cin >> node[i].x >> node[i].y >> node[i].l;
	}

	init();


	sort(node + 1, node + m + 1, cmp);

	for (int i = 1; i <= m; i++)
	{
		if (find(node[i].x) != find(node[i].y))
		{
			unions(node[i].x, node[i].y);
			ans += node[i].l;
			sum++;
		}
		if (sum == n - k)
		{
			cout << ans;
			return 0;
		}
	}

	cout << "No Answer";
}

拓扑排序

1.拓扑排序模板

以vector存储图,队列实现topo:

#include
#include
#include
#define maxn 1000

using namespace std;

int in[maxn],int out[maxn];//入度,出度数组

vectoredge[maxn];//edge[n][0]表示第n个节点第一条边连接的节点
vectorans;//拓扑序列

queueq;

int main()
{
	for (int i = 0; i < n; i++)//寻找入度为0节点入队
		if (in[i] == 0)
			q.push(i);

	while (!q.empty())      //循环出队并判断,直到找不到入度为0的节点
	{
		int p = q.front();
		q.pop();            //出队
		ans.push_back(p);   //加入拓扑序列
		for (int i = 0; i < edge[p].size(); i++)
		{   //将与之相连的节点入度-1
			in[edge[p][i]]--;
			if (in[edge[p][i] == 0])
				q.push(edge[p][i]);
		}
	}

	if (ans.size() == n)    //所有节点入拓扑序列,即无环
	{
		for (int i = 0; i < ans.size(); i++)
			cout << ans[i] << " ";
	}
	else
		cout << "No Answer";
}

2.拓扑排序例题

最大食物链计数(洛谷P4017)

题目描述:求食物网中最大食物链数量

输入:第一行生物种数n,关系数m,接下来m行每行两个正整数,表示被吃的A和吃A的B

输出:一个整数,为最大食物链数量模上 8011200280112002 的结果

分析:参见 洛谷P4017 最大食物链计数 题解 - 御·Dragon - 博客园

#include
#include
#include
#include
#include
#define maxn 5005

using namespace std;

int n, m;
const int mod = 80112002;

int in[maxn],out[maxn];
vectoredge[maxn];
int num[maxn];//记录到每个点的路径数

queueq;
int ans;

int main()
{
	cin >> n >> m;
	int x, y;

	for (int i = 1; i <= m; i++)//存图
	{
		cin >> x >> y;
		++in[y], ++out[x];
		edge[x].push_back(y);
	}

	for (int i = 1; i <= n; i++)//寻找入度为0节点
	{
		if (!in[i])
		{
			num[i] = 1;
			q.push(i);
		}
	}

	while (!q.empty())
	{
		int f = q.front();
		q.pop();
		for (int i = 0; i < edge[f].size();i++)
		{
			int next = edge[f][i];
			--in[next];
			num[next] = (num[next] + num[f]) % mod;
			if (in[next] == 0)
			{
				q.push(next);
			}
		}
	}

	for (int i = 1; i <= n; i++)
	{
		if (!out[i])
		{
			ans = (ans + num[i]) % mod;
		}
	}
	cout << ans;
}

你可能感兴趣的:(算法,图论,算法,c++,c语言)