链接: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);
}
}