2023/2/15总结

P3884 [JLOI2009]二叉树问题

题目描述

如下图所示的一棵二叉树的深度、宽度及结点间距离分别为:

  • 深度:44
  • 宽度:44
  • 结点 8 和 6 之间的距离:88
  • 结点 7 和 6 之间的距离:33

其中宽度表示二叉树上同一层最多的结点个数,节点 �,�u,v 之间的距离表示从 �u 到 �v 的最短有向路径上向根节点的边数的两倍加上向叶节点的边数。

2023/2/15总结_第1张图片

给定一颗以 1 号结点为根的二叉树,请求出其深度、宽度和两个指定节点 �,�x,y 之间的距离。

输入格式

第一行是一个整数,表示树的结点个数 �n。
接下来 �−1n−1 行,每行两个整数 �,�u,v,表示树上存在一条连接 �,�u,v 的边。
最后一行有两个整数 �,�x,y,表示求 �,�x,y 之间的距离。

输出格式

输入三行,每行一个整数,依次表示二叉树的深度、宽度和 �,�x,y 之间的距离。

输入输出样例

输入 #1复制

10                                
1 2                            
1 3                            
2 4
2 5
3 6
3 7
5 8
5 9
6 10
8 6

输出 #1复制

4
4
8

说明/提示

对于全部的测试点,保证 1≤�,�,�,�≤�≤1001≤u,v,x,y≤n≤100,且给出的是一棵树。

题解:

1: 用dfs求深度

2:用一个cnt数组,记录根经过某个距离所能到达的结点数,cnt表示某个距离;根到 i 有相同距离的点,说明在同一层;直接计算根能到达的点,cnt[a[1][i]]++;

3:用二阶矩阵存图,利用floyd求最短距离

代码:

#include
using namespace std;
int n, depth, width;
int a[105][105];
int vis[105];
int cnt[205];
void dfs(int u, int step) {
    for (int i = 1; i <= n; ++i) {
        if (!vis[i] && a[u][i] != 1000) {
            depth = max(depth, step);
            vis[i] = 1;
            dfs(i, step + 1);
            vis[i] = 0;
        }
    }
}
int main() {
    for (int i = 1; i <= 105; ++i) {
        for (int j = 1; j <= 105; ++j) {
            a[i][j] = 1000;
        }
    }
    memset(vis, 0, sizeof vis);
    cin >> n;
    int u, v, x, y;
    for (int i = 0; i < n - 1; ++i) {
        cin >> u >> v;
        a[u][v] = 1;
        a[v][u] = 2;
    }
    cin >> x >> y;
    dfs(1, 0);
    for (int k = 1; k <= n; ++k) {
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                a[i][j] = min(a[i][j], a[i][k] + a[k][j]);
            }
        }
    }
    for (int i = 2; i <= n; ++i) {
        cnt[a[1][i]]++;
    }
    for (int i = 1; i <= 205; ++i) {
        width = max(width, cnt[i]);
    }
    cout << depth << endl;
    cout << width << endl;
    cout << a[x][y];
    return 0;
}

P2256 一中校运会之百米跑

题目背景

在一大堆秀恩爱的 ** 之中,来不及秀恩爱的苏大学神踏着坚定(?)的步伐走向了 100100 米跑的起点。这时苏大学神发现,百米赛跑的参赛同学实在是太多了,连体育老师也忙不过来。这时体育老师发现了身为体育委员的苏大学神,便来找他帮忙。

可是苏大学神需要热身,不然跑到一半就会抽(筋)、于是他就找到了你。。。如果你帮助体育老师解决了问题,老师就会给你 55 个积分。

题目描述

假设一共有 �N(2≤�≤2×1042≤N≤2×104)个参赛选手。(尼玛全校学生都没这么多吧)

老师会告诉你这 �N 个选手的名字。

接着会告诉你 �M(1≤�≤1061≤M≤106)句话,即告诉你学生 A 与学生 B 在同一个组里。

如果学生 A 与学生 B 在同一组里,学生 B 与学生 C 也在同一组里,就说明学生 A 与学生 C 在同一组。

然后老师会问你 �K(1≤�≤1061≤K≤106)句话,即学生 X 和学生 Y 是否在同一组里。

若是则输出 Yes.,否则输出 No.

输入格式

第一行输入 �N 和 �M。

接下来 �N 行输入每一个同学的名字。

再往下 �M 行每行输入两个名字,且保证这两个名字都在上面的 �N 行中出现过,表示这两个参赛选手在同一个组里。

再来输入 �K。

接下来输入 �K 个体育老师的询问。

输出格式

对于每一个体育老师的询问,输出 Yes. 或 No.

输入输出样例

输入 #1复制

10 6
Jack
Mike
ASDA
Michel
brabrabra
HeHe
HeHE
papapa
HeY
Obama
Jack Obama
HeHe HeHE
brabrabra HeHe
Obama ASDA
papapa Obama
Obama HeHE
3
Mike Obama
HeHE Jack
papapa brabrabra

输出 #1复制

No.
Yes.
Yes.

题解:
1:套入并查集模板。

2:把字符串利用哈希转换成特定的数字

代码:

#include
using namespace std;
string s3,s1,s2;
int n,m,a[200009],k;
int seed=233;
int fa[200009];
int find(int x)
{
	if(fa[x]==x) return x;
	return fa[x]=find(fa[x]);
}
int has(string s){
	unsigned long long hash_=0;
	for(int i=0;i>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>s3;
		fa[has(s3)]=has(s3);
	}
	for(int i=1;i<=m;i++)
	{
		cin>>s1>>s2;
		fa[find(has(s2))]=find(has(s1));
	}
	cin>>k;
	for(int i=1;i<=k;i++)
	{
		cin>>s1>>s2;
		if(find(has(s1))!=find(has(s2))) cout<<"No."<

你可能感兴趣的:(算法,数据结构)