(https://acm.ecnu.edu.cn/contest/173/problem/C/)
题目大意:
小花梨给出?个点,让?位同学对这?个点任意添加无向边,构成?张图。小花梨想知道对于每个点?,存在多少个点?(包括?本身),使得?和?在这?张图中都是连通的。
题解:
- 直接DFS、BFS或者并查集对每张图进行连通块染色, 两个点在k张图中都相邻说明这两个点在k张图的染色 都是一样的
- map<vector< int >,int>存下每个点在k张图的颜色序列出现的次数即可。
DFS(深搜):
/*AC 1.008*/
#include<iostream>
#include<vector>
#include<map>
const int MAX=1e5+10;
using namespace std;
int nowcolor,n,k;
bool book[MAX];
vector<int>G[MAX];
vector<int>color[MAX];
map<vector<int>,int>Map;
void dfs(int i)
{
book[i]=1;color[i].push_back(nowcolor);
for(int j=0;j<G[i].size();j++)
if(!book[G[i][j]])dfs(G[i][j]);
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);
cin>>n>>k;
while(k--)
{
for(int w=1;w<=n;w++)G[w].clear(),book[w]=0;
int a,u,v;
cin>>a;
for(int i=1;i<=a;i++)
cin>>u>>v,
G[u].push_back(v),
G[v].push_back(u);
nowcolor=0;
for(int i=1;i<=n;i++)
if(!book[i])nowcolor++,dfs(i);
}
for(int i=1;i<=n;i++)
Map[color[i]]++;
for(int i=1;i<=n;i++)
cout<<Map[color[i]]<<endl;
return 0;
}
BFS(广搜):
/*AC 0.739*/
#include<bits/stdc++.h>
#define _ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int MAX=1e5+10;
vector<int>G[MAX];
vector<int>color[MAX];
int que[MAX];
map<vector<int>,int>Map;
bool book[MAX];
int main()
{_
int n,k;
cin>>n>>k;
while(k--)
{
for(int i=1;i<=n;i++)
G[i].clear(),book[i]=0;
int a,u,v,nowcolor;
cin>>a;
for(int i=1;i<=a;i++)
cin>>u>>v,G[u].push_back(v),G[v].push_back(u);
nowcolor=0;
for(int i=1;i<=n;i++){
if(!book[i]){
nowcolor++;
int head=1,tail=1;
que[tail++]=i;
book[i]=1;
color[i].push_back(nowcolor);
while(head<tail/*&&tail<=n*/)
{
int t=que[head];
for(int j=0;j<G[t].size();j++){
if(!book[G[t][j]]){
que[tail++]=G[t][j];
book[G[t][j]]=1;
color[G[t][j]].push_back(nowcolor);
}
//if(tail>n)break;
}
head++;
}
}
}
}
for(int i=1;i<=n;i++)
Map[color[i]]++;
for(int i=1;i<=n;i++)
cout<<Map[color[i]]<<endl;
return 0;
}
并查集:
/*AC 0.345*//*(以下代码借鉴自其他博客)*/
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int N=1e5+20;
vector<int>zu[N];
map<vector<int>,int>mp;
int pre[N],num[N];
int find(int x)//并查集的查操作
{
if(pre[x]==x)
return x;
return pre[x]=find(pre[x]);
}
void merge(int x,int y)//并查集的并操作
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
if(num[fx]>num[fy])
{
pre[fy]=fx;
num[fx]+=num[fy];
}
else
{
pre[fx]=fy;
num[fy]+=num[fx];
}
}
return;
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int z=0;z<k;z++)//依次处理k张图,正在处理的图记为第z张图
{
for(int i=1;i<=n;i++)//并查集初始化
{
pre[i]=i;
num[i]=1;
}
int m,x,y;
scanf("%d",&m);
for(int i=0;i<m;i++)//m个边
{
scanf("%d%d",&x,&y);
merge(x,y);
}
for(int i=1;i<=n;i++)//将每个点的第z个祖先push_back到zu[i]的vector中
zu[i].push_back(find(i));
}
for(int i=1;i<=n;i++)//用map统计完全相同的zu[i]的个数
mp[zu[i]]++;
for(int i=1;i<=n;i++)//输出完全相同的zu[i]的个数,即和点i在k张图中都全连通的点的数量
printf("%d\n",mp[zu[i]]);
return 0;
}