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

链接: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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值