• $ACM$ 课第五次作业-图论


    (ACM) 课第五次作业-图论


    (A. PET)

    题意

    给定一颗 (n) 个节点的有根树,统计深度大于 (d) 的节点数量

    输入格式

    多组数据,(d < nleq 100000)

    输出格式

    输出深度大于 (d) 的节点数量

    题解

    树上 (dfs) 即可

    由于内存限制,下面给出链式前向星和 (vector) 的实现

    注意,初始化 (vector) 时下标从 (0) 开始,以及链式前向星的数组开大点

    (code)

    /*vector*/
    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int MOD = 1e9 + 7;
    const int N = 1e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
    
    int t, n, d;
    vector<int> g[N];
    void dfs(int cur, int fa, int step, int &ans)
    {
        if(step > d) ans++;
        for(auto i: g[cur])
            if(i != fa) dfs(i, cur, step + 1, ans);
    }
    int main()
    {
        t = read();
        while(t--) {
            n = read(), d = read();
            for(int i = 0; i < n; ++i) g[i].clear();
            for(int i = 1; i < n; ++i) {
                int a = read(), b = read();
                g[a].push_back(b);
            }
            int ans = 0;
            dfs(0, -1, 0, ans);
            printf("%d
    ", ans);
        }
        return 0;
    }
    /*
    */
    
    /*链式前向星*/
    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int MOD = 1e9 + 7;
    const int N = 1e6 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
    
    int t, n, d, ans;
    int cnt, head[N];
    struct edge
    {
        int to, next;
    }e[N];
    
    void addedge(int a, int b)
    {
        e[cnt].to = b;
        e[cnt].next = head[a];
        head[a] = cnt++;
    }
    void dfs(int cur, int fa, int step, int &ans)
    {
        if(step > d) ans++;
        for(int i = head[cur]; ~i; i = e[i].next) {
            int to = e[i].to;
            if(to != fa) dfs(to, cur, step + 1, ans);
        }
    }
    int main()
    {
        t = read();
        while(t--) {
            memset(head, -1, sizeof(head));
            n = read(), d = read();
            for(int i = 1; i < n; ++i) {
                int a = read(), b = read();
                addedge(a, b);
            }
            int ans = 0;
            dfs(0, -1, 0, ans);
            printf("%d
    ", ans);
        }
        return 0;
    }
    /*
    */
    

    (B.) 哈密顿绕行世界问题

    题意

    给定 (20) 个点,每个点分别与另外 (3) 个点有一条有向边

    给定起点,求所有回到起点的哈密顿回路,即经过起点两次,经过其他节点一次的路径

    输入格式

    多组数据

    输出格式

    输出路径,按字典序非降序排序

    题解

    哈密顿回路,直接 (dfs) 即可

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int MOD = 1e9 + 7;
    const int N = 2e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
    
    int m, vis[100];
    vector<int> g[100], path;
    vector< vector<int> > ans;
    void dfs(int cur, int step)
    {
        if(step == 21) {
            if(cur == m) ans.pb(path);
            return;
        }
        for(auto i: g[cur]) {
            if(!vis[i] || vis[i] && i == m && step == 20) {
                path.pb(i);
                if(i != m) vis[i] = 1;
                dfs(i, step + 1);
                path.erase(--path.end());
                if(i != m) vis[i] = 0;
            }
        }
    }
    bool cmp(vector<int> v1, vector<int> v2)
    {
        for(int i = 0; i < v1.size(); ++i){
            if(v1[i] < v2[i]) return 1;
            else if(v1[i] > v2[i]) return 0;
        }
        return 1;
    }
    void solve()
    {
        path.pb(m);
        vis[m] = 1;
        dfs(m, 1);
        sort(ans.begin(), ans.end(), cmp);
        for(int i = 0; i < ans.size(); ++i) {
            printf("%d:  ", i + 1);
            for(int j = 0; j < ans[i].size(); ++j)
                printf("%d%c", ans[i][j], " 
    "[j == ans[i].size() - 1]);
        }
    }
    int main()
    {
        for(int i = 1; i <= 20; ++i) {
            int a = read(), b = read(), c = read();
            g[a].pb(i), g[b].pb(i), g[c].pb(i);
        }
        while(cin >> m && m) {
            memset(vis, 0, sizeof(vis));
            path.clear();
            solve();
        }
        return 0;
    }
    /*
    */
    

    (C.) 六度分离

    题意

    六度分离理论这么说道:任意两个不认识的人之间至多隔了 (6) 个人

    现给定 (n) 个人,(m) 个关系,验证六度分离理论是否成立

    输入格式

    多组数据,(nleq 100, mleq 200)

    输出格式

    若六度分离理论成立,输出 (Yes)

    若不成立,输出 (No)

    题解

    (floyed) 求任意两点之间的最短路,枚举点逐一 (check) 即可

    注意一下 (floyed) 算法的枚举顺序,松弛的中点 (k) 在最外层

    (code)

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int MOD = 1e9 + 7;
    const int N = 2e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
    
    
    int n, m, g[500][500], dis[500][500];
    void floyed()
    {
        memset(dis, inf, sizeof(dis));
        for(int i = 0; i < n; ++i)
            for(int j = 0; j < n; ++j)
                if(g[i][j] || i == j) dis[i][j] = g[i][j];
        for(int k = 0; k < n; ++k)
            for(int i = 0; i < n; ++i)
                for(int j = 0; j < n; ++j)
                    dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
    }
    bool check()
    {
        floyed();
        for(int i = 0; i < n; ++i)
            for(int j = 0; j < n; ++j)
                if(g[i][j] != inf && dis[i][j] > 7) return 0;
        return 1;
    }
    int main()
    {
        while(~scanf("%d %d", &n, &m)) {
            memset(g, 0, sizeof(g));
            for(int i = 1; i <= m; ++i) {
                int a = read(), b = read();
                g[a][b] = g[b][a] = 1;
            }
            int flag = check();
            if(flag) puts("Yes");
            else puts("No");
        }
        return 0;
    }
    /*
    */
    

    (D. Watchcow)

    题意

    给定 (n) 个点,(m) 条双向边,求出从起点 (1) 出发的欧拉回路,即经过每条边各一次的回路

    输入格式

    (nleq 10000, Mleq 50000)

    输出格式

    输出从起点 (1) 出发的欧拉回路

    题解

    欧拉回路模板题

    用链式前向星维护边,(dfs) 一遍,回溯时记录答案,最后倒序输出即可

    由于本题是双向边,答案不一定要倒序输出

    (code)

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <math.h>
    #include <algorithm>
    #include <vector>
    #define fi first
    #define se second
    #define pii pair<int, int>
    #define pb push_back
    #define arrayDebug(a, l, r) for(int i = l; i <= r; ++i) printf("%d%c", a[i], " 
    "[i == r])
    typedef long long LL;
    typedef unsigned long long ULL;
    const LL INF = 0x3f3f3f3f3f3f3f3f;
    const int inf = 0x3f3f3f3f;
    const int DX[] = {0, -1, 0, 1, 0, -1, -1, 1, 1};
    const int DY[] = {0, 0, 1, 0, -1, -1, 1, 1, -1};
    const int MOD = 1e9 + 7;
    const int N = 5e5 + 7;
    const double PI = acos(-1);
    const double EPS = 1e-6;
    using namespace std;
    inline int read()
    {
        char c = getchar();
        int ans = 0, f = 1;
        while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
        while(isdigit(c)) {ans = ans * 10 + c - '0'; c = getchar();}
        return ans * f;
    }
    
    int n, m;
    int cnt = 1, head[N];
    struct node
    {
        int to, next, vis;
    }e[N];
    void addEdge(int a, int b)
    {
        e[cnt].to = b;
        e[cnt].next = head[a];
        e[cnt].vis = 0;
        head[a] = cnt++;
    }
    vector<int> ans;
    void dfs(int m)
    {
        for(int i = head[m]; ~i; i = e[i].next) {
            if(!e[i].vis && e[i].to != -1) {
                e[i].vis = 1;
                dfs(e[i].to);
            }
        }
        ans.pb(m);
    }
    int main()
    {
        memset(head, -1, sizeof(head));
        ans.clear();
        n = read(), m = read();
        for(int i = 1; i <= m; ++i) {
            int a = read(), b = read();
            addEdge(a, b), addEdge(b, a);
        }
        dfs(1);
        for(int i = ans.size() - 1; i >= 0; --i) printf("%d
    ", ans[i]);//倒序输出
        return 0;
    }
    /*
    3 3
    1 2
    2 3
    3 1
    */
    
  • 相关阅读:
    EF Relationships
    HTTP Error 500.31 Failed to load ASP.NET Core runtime
    The entity type 'Vehicle' cannot be configured as owned because it has already been configured as a nonowned.
    为什么样本方差(sample variance)的分母是 n1?
    Python String Slicing
    How I can obtain the collation of a specific table in a database?
    After Effects 2022.11.12
    Use Where Clause With Merge
    EF Core HasMany vs OwnsMany
    What is Owned Entity? When and why to use Owned Entity in Entity Framework Core?
  • 原文地址:https://www.cnblogs.com/ChenyangXu/p/12825865.html
Copyright © 2020-2023  润新知