2022“杭电杯”中国大学生算法设计超级联赛(7) 2022杭电多校第七场

本文提供两道竞赛编程题目解析及AC代码实现,包括独立反馈顶点集问题与火柴人数目计算问题,涵盖图论、二分图等知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1002 Independent Feedback Vertex Set

**Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 346 Accepted Submission(s): 210
**

Problem Description

Yukikaze loves graph theory, especially forests and independent sets.

  • Forest: an undirected graph without cycles.
  • Independent set: a set of vertices in a graph such that for every two vertices, there is no edge connecting the two.

Yukikaze has an undirected graph G=(V,E) where V is the set of vertices and E is the set of edges. Each vertex in V has a vertex weight. Now she wants to divide V into two complementary subsets VI and VF such that VI is an independent set, and the induced subgraph G[VF] is a forest. The induced subgraph G[VF] is the graph whose vertex set is VF and whose edge set consists of all of the edges in E that have both endpoints in VF. In addition, she wants to maximize the sum of weights of vertices in VI.

Since this problem is NP-hard for general graphs, she decides to solve a special case of the problem. We can build a special graph by the following steps. Initially, the graph consists of three vertices 1,2,3 and three edges (1,2),(2,3),(3,1). When we add a vertex x into the graph, we select an edge (y,z) that already exists in the graph and connect (x,y) and (x,z). Keep doing this until there are n vertices in the graph.

Input

The first line of the input contains a single integer T (1≤T≤103), indicating the number of test cases.

The first line of each test case contains a single integer n (4≤n≤105), indicating the number of vertices in the graph. It is guaranteed that the sum of n over all test cases won’t exceed 106.

The second line of each test case contains n positive integers a1,a2,…,an (1≤ai≤109), indicating the weights of the vertices.

Initially, the graph consists of three vertices 1,2,3 and three edges (1,2),(2,3),(3,1). The i-th line of the next n−3 lines contains two integers u,v (1≤u,v<i+3), indicating the addition of a vertex i+3 and two edges (i+3,u),(i+3,v) to the graph. It is guaranteed that (u,v) already exists in the graph.

Output

For each test case, print an integer in a single line indicating the maximum sum of weights of vertices in VI.

Sample Input

3
4
3 3 2 2
1 2
4
2 5 5 2
2 3
5
3 1 1 1 1
1 2
1 3

Sample Output

4
5
3

Source

2022“杭电杯”中国大学生算法设计超级联赛(7)

有n个点,每个点有对应的权重,1,2,3号点两两相连,从第四号点开始,给出两个点,这两点这之间存在边,将该点和这两个点进行连接,你需要选择一些点,这些点两两之间不存在边,且剩下的点构成一个无环的无向图
我们先考虑开始的三角形,如果三个点都选上或者任选两个点,那就违背了我们说的两两不存在边,但如果都不选,那么剩下的图一定有环,所以我们必须在三个点中选择一个点,我们枚举这个情况并确定二分图,最后遍历得到答案即可

tags:二分图

AC代码

/****************

 *@description:for the Escape Project

 *@author: Nebula_xuan

 * @Date: 2022-08-10 16:37:46

 *************************************************************************/

  

#include <iostream>

#include <algorithm>

#include <cstring>

#include <cstdio>

#include <set>

#include <vector>

#include <queue>

#include <map>

#include <cmath>

  

using namespace std;

  

#define xx first

#define yy second

#define rep(i, h, t) for (int i = h; i <= t; i++)

#define dep(i, t, h) for (int i = t; i >= h; i--)

#define endl char(10)

#define int long long

//记得%d应该写成%lld

  

typedef pair<int, int> PII;

typedef long long ll;

const int N = 1e5 + 10;

int a[N];

signed main()

{

    ios::sync_with_stdio(false);

    int t;

    cin >> t;

    while (t--)

    {

        int n;

        cin >> n;

        vector<PII> e(n + 1);

        int ans = 0;

        for (int i = 1; i <= n; i++)

            cin >> a[i];

        for (int i = 4; i <= n; i++)

            cin >> e[i].xx >> e[i].yy;

        for (int i = 1; i <= 3; i++)

        {

            vector<int> c(n + 1);

            c[i] = 1;

            int res = a[i];

            for (int j = 4; j <= n; j++)

            {

                int u = e[j].xx, v = e[j].yy;

                if (c[u] == c[v] && c[u] == 0)

                {

                    c[j] = 1;

                    res += a[j];

                }

            }

            ans = max(ans, res);

        }

        cout << ans << endl;

    }

}

1003 Counting Stickmen

**Time Limit: 18000/9000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 871 Accepted Submission(s): 283
**

Problem Description

Namesolo has fallen in love with the game Stick Fight. But when he is playing the game, he wonders how to find out the number of stickmen in the game.

In this question, we define the stick man as shown in the picture above. It has a chain of length 1 as the head, two chains of length 2 as the arms, a chain of length 1 as the body, and two chains of length 1 as the legs. For example, the red part in this picture can be viewed as a stick man, with chain (2,3) to be the head, chains (3,4,6) and (3,9,10) to be the arms, chain (3,5) to be the body, and chains (5,7) and (5,8) to be the legs.

The game can be viewed as a tree, and Namesolo wants to know how many stickmen are there. Please note that two stickmen are different when there is at least one different edge between the two edge sets that make up the two stickmen.

Because the answer may be too large, Namesolo wants to know the answer modulo 998244353.

Input

The first line of input contains one integer T (1≤T≤15), indicating the number of test cases.

For each test case, the first line contains an integer n (1≤n≤5×105), indicating the number of vertices in the tree. Each of the following n−1 lines contains two integers a,b (1≤a,b≤n), indicating that there is an edge connecting a and b in the tree.

It is guaranteed that the sum of n over all cases won’t exceed 3×106.

Output

For each test case, output an integer representing the answer modulo 998244353.

Sample Input

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

Sample Output

1

Source

2022“杭电杯”中国大学生算法设计超级联赛(7)

给你一个图,问你有多少个火柴人,其中火柴人的定义是头的长度为1,手的长度为2,身体的长度为1,腿的长度为2
这里我们以“脖子”为核心,然后找子节点的度数即可
![[Pasted image 20220810213358.png]]
对于火柴人的手来说,所有度数大于等于2的子节点都能当作手用
对于度数大于等于3的子节点,都可以当作身体,所以我们还要记录一下子节点的度数,因为脚只要选两条即可,即 C n 2 C_{n}^{2} Cn2种方案,其中n表示子节点的子节点的个数
但是要注意当把身体当作手来用的时候,这样是不合法的,删去即可

AC代码

/****************

 *@description:for the Escape Project

 *@author: Nebula_xuan

 * @Date: 2022-08-10 21:40:00

 *************************************************************************/

  

#include <iostream>

#include <algorithm>

#include <cstring>

#include <cstdio>

#include <set>

#include <vector>

#include <queue>

#include <map>

#include <cmath>

  

using namespace std;

  

#define xx first

#define yy second

#define rep(i, h, t) for (int i = h; i <= t; i++)

#define dep(i, t, h) for (int i = t; i >= h; i--)

#define endl char(10)

#define int long long

//记得%d应该写成%lld

  

typedef pair<int, int> PII;

typedef long long ll;

const int N = 2e6 + 10;

int e[N], ne[N], idx, h[N], d[N], hand[N], body[N];

const int MOD = 998244353;

int ans = 0;

void add(int a, int b)

{

    e[idx] = b, ne[idx] = h[a], h[a] = idx++;

}

int work(int n)

{

    return n * (n - 1) / 2;

}

void dfs(int u, int fa)

{

    int cnth = 0, cntb = 0;

    int temp = 0;

    for (int i = h[u]; ~i; i = ne[i])

    {

        int v = e[i];

        cnth += hand[v];

        cntb += body[v];

        if (v == fa)

            continue;

        dfs(v, u);

    }

    if (d[u] <= 3)

        return;

    for (int i = h[u]; ~i; i = ne[i])

    {

        int v = e[i];

        temp += ((d[u] - 3) * body[v] % MOD) * ((work(cnth - hand[v]) - (cntb - body[v])) % MOD)%MOD;

        temp %= MOD;

    }

    ans += temp;

    ans %= MOD;

}

signed main()

{

    ios::sync_with_stdio(false);

    int t;

    cin >> t;

    while (t--)

    {

        ans = 0;

        idx = 0;

        int n;

        cin >> n;

        for (int i = 0; i <= 2 * n + 100; i++)

        {

            e[i] = ne[i] = hand[i] = body[i] = 0;

            h[i] = -1;

            d[i] = 0;

        }

        for (int i = 1; i < n; i++)

        {

            int a, b;

            cin >> a >> b;

            d[a]++, d[b]++;

            add(a, b);

            add(b, a);

        }

        for (int i = 1; i <= n; i++)

        {

            hand[i] = d[i] - 1;

            if (d[i] >= 3)

                body[i] = work(d[i] - 1);

        }

        dfs(1, 0);

        cout << ans << endl;

    }

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

能工智人小辰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值