牛客OI周赛11-普及组 C Colorful

探讨在给定的无向图中寻找一棵生成树,使所用颜色种类最少的算法问题。通过二进制枚举可用颜色,利用并查集判断图的连通性,确保生成树的有效性和颜色优化。

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

链接:https://ac.nowcoder.com/acm/contest/942/C
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

小A最近学习了最小生成树的算法,觉得非常神奇。
他现在在研究一个更加神奇的问题

给定nn个点mm条边的无向图,每条边都有一个颜色,请找到一棵生成树,满足颜色的种类尽量少

保证图联通

输入描述:

第一行数据组数TT
对于每一组数据,第一行n,m,sn,m,s,分别代表点数,边数,颜色种类数量
接下来mm行,每行三个整数u,v,cu,v,c,代表一条边和它的颜色

输出描述:

对于每组数据输出一行一个整数表示答案

示例1

输入

复制

1
3 3 2
1 2 1
2 3 1
1 3 2

输出

复制

1

说明

选择边(1,2)(1,2)和(2,3)(2,3)

示例2

输入

复制

1
6 8 4
1 2 1
2 3 2
3 4 3
3 5 4
5 6 2
4 6 1
3 5 2
1 3 4

输出

复制

2

备注:

对于10%10%的数据,1≤n,m≤101≤n,m≤10
对于40%40%的数据,1≤n,m≤1001≤n,m≤100 , 1≤s≤121≤s≤12
对于另外20%20%的数据,1≤n≤1001≤n≤100,1≤m≤1051≤m≤105,1≤s≤61≤s≤6
对于100%100%的数据,1≤n≤1001≤n≤100,1≤m≤1051≤m≤105,1≤c≤s≤121≤c≤s≤12 , 1≤T≤51≤T≤5
可能有重边,保证没有自环

 

二进制枚举可以利用的颜色

然后判图的连通性

根据颜色分类边,利用并查集判图的连通性,

各种方法会T

需要预处理每种颜色使得图的联通关系

比较好的题吧

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+46;
struct EDGE
{
    int from,to,colour,nxt;
};
inline void read(int &x)
{
    char ch = getchar();
    while (ch != '+' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '+') ch = getchar();
    x = 0;
    while ('0' <= ch && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
}
EDGE edge[maxn];
int flag[13];
int head[maxn];
int had_gone[105];
int all=0;
int cnt=0;
int mp[105][105][15];
int fa[105];
vector<pair<int,int> >v[15];
void init()
{
    memset(head,-1,sizeof(head));
    memset(had_gone,0,sizeof(had_gone));
    cnt=0;
    all=0;
    memset(edge,0,sizeof(edge));
}
void add(int x,int y,int col)
{
    edge[cnt].from=x;
    edge[cnt].to=y;
    edge[cnt].colour=col;
    edge[cnt].nxt=head[x];
    head[x]=cnt;
    cnt++;
}
void dfs(int n)
{
    had_gone[n]=1;
    all++;
    for(int i=head[n]; i!=-1; i=edge[i].nxt)
    {
        if(flag[edge[i].colour]&&!had_gone[edge[i].to])
        {
            dfs(edge[i].to);
        }
    }
}
int fin(int x)
{
    return fa[x]=fa[x]==x?x:fin(fa[x]);
}
int father[15][105];
int  find_col(int col,int x)
{
    return father[col][x]=father[col][x]==x?x:find_col(col,father[col][x]);
}
int main()
{
    int t;
    read(t);
    while(t--)
    {
        memset(mp,0,sizeof(mp));
        int ans=maxn;
        int n,m,s;
        cnt=0;
        //init();
        for(int i=0; i<15; i++)
        {
            for(int j=0; j<105; j++)
            {
                father[i][j]=j;
            }
        }
        for(int i=0; i<15; i++)
            v[i].clear();
        memset(flag,0,sizeof(flag));
        //scanf("%d%d%d",&n,&m,&s);
        read(n);
        read(m);
        read(s);
        int x,y,col;
        for(int i=0; i<m; i++)
        {
            //scanf("%d%d%d",&x,&y,&col);
            read(x);
            read(y);
            read(col);
            if(!mp[x][y][col])
            {
                v[col].push_back(make_pair(x,y));
                mp[x][y][col]=1;
                //add(x,y,col);
                // add(y,x,col);
            }
        }
        for(int col=1; col<=s; col++)
        {
            for(int i=0; i<v[col].size(); i++)
            {
                father[col][find_col(col,v[col][i].first)]=find_col(col,v[col][i].second);
            }
        }
        for(int cas=0; cas<(1<<s); cas++)
        {
            all=0;
            memset(flag,0,sizeof(flag));
            //memset(had_gone,0,sizeof(had_gone));
            int num=cas;
            int c=1;
            int hi=0;
//            bitset <4>f(cas);
//            cout<<f<<endl;
            while(num)
            {
                if(num&1)
                {
                    flag[c]=1;
                    hi++;
                }
                c++;
                num>>=1;
            }
            if(hi>=ans)
                continue;

            for(int i=0; i<105; i++)
                fa[i]=i;
            for(int col=1; col<=s; col++)
            {
                if(flag[col])
                {
                    for(int i=1; i<=n; i++)
                    {
                        fa[fin(find_col(col,i))]=fin(i);
                    }
                }
            }
            all=1;
//            for(int i=1;i<=n;i++)
//            {
//                printf("%d ",fa[i]);
//            }
//            printf("\n");
            for(int i=2; i<=n; i++)
            {
                if(fin(i)==fin(1))
                    all++;
            }
            //for(int i=4;i>=1;i--)
            //    printf("%d",flag[i]);
            //cout<<endl;
            //printf("%d")
            //dfs(n);
            //printf("%d\n",all);
            if(all==n)
            {
                ans=min(ans,hi);
            }
        }
        printf("%d\n",ans);
    }
}

 

 

### 关于京东牛客网技术运维工程师笔试题目与经验 #### 笔试内容概述 技术运维工程师的笔试通常会涉及计算机基础、网络协议、操作系统原理以及实际问题解决能力等方面的知识。根据以往的经验,京东的技术运维工程师笔试可能包括但不限于以下几个方面[^1]: - **基础知识**:数据结构与算法的基础应用,例如数组、链表的操作,排序算法的选择与实现。 - **网络知识**:TCP/IP 协议栈的理解,HTTP/HTTPS 的工作流程,DNS 解析过程等。 - **Linux 操作系统**:Shell 编程、进程管理、文件权限控制等内容。 - **数据库操作**:SQL 查询语句优化,索引设计,事务处理机制。 以下是几个常见的考察方向及其对应的示例问题: #### 数据结构与算法实例 ```python def find_missing_number(nums): n = len(nums) + 1 expected_sum = n * (n + 1) // 2 actual_sum = sum(nums) return expected_sum - actual_sum ``` 此函数用于在一个长度为 `n` 的列表中找到缺失的一个整数,假设该列表原本应包含从 1 到 `n` 的连续正整数序列[^1]。 #### Linux Shell 实现脚本 编写一个简单的 Bash 脚本来监控磁盘空间并发送警告邮件给管理员: ```bash #!/bin/bash THRESHOLD=90 CURRENT=$(df / | grep / | awk '{ print $5}' | sed 's/%//g') if [ "$CURRENT" -gt "$THRESHOLD" ]; then echo "Warning: Disk space is low." | mail -s "Disk Space Alert" admin@example.com fi ``` 这段代码展示了如何通过命令行工具检测根目录下的可用存储容量,并在超过设定阈值时触发警报通知[^3]。 #### SQL 查询技巧 对于大规模关系型数据库中的性能调优而言,合理创建复合索引可以显著提升查询效率。比如,在一张记录用户活动日志的大表里查找特定时间段内的活跃用户数量时,应该考虑对日期字段建立覆盖索引来减少全表扫描带来的开销。 --- ###
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值