目录
图的常用存储方式
1.邻接矩阵
2.邻接表
3.链式前向星
4.Vector存储(我最喜欢用的)
并查集
1.并查集模板
2.并查集例题
拓扑排序
1.拓扑排序模板
2.拓扑排序例题
详:图的几种存储方式_roadkiller.的博客-CSDN博客_图的存储方式
int map[maxn][maxn];
map[i][j]=w //表示第i个顶点到第j个顶点有权值为w的边
struct edgeNode
{
int adjvex;//点
int w; //权值
struct edgeNode* next;//指向下一条边
};
struct edge
{
int start;//起点
int to; //终点
int cost; //权值
};
struct edge
{
int to; //当前边的终点
int w ; //权值
int next //下一条边的下标
};
vectoredge[maxn];
//edge[n][i-1]表示第n个节点第i条边连接的顶点
//edge[n].size()表示与第n个节点相连的顶点数(边数)
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;
}
口袋的天空(洛谷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";
}
以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";
}
最大食物链计数(洛谷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;
}