题目大意:
有 \(n\) 名员工,一共有 \(m\) 种语言,每名员工都会其中 \(k_i\) 种语言(\(m \ge \boldsymbol{k_i \ge 0}\)),现规定两名员工可以交流的条件如下:
- 两名员工会一种及以上共同的语言。
- 有一名员工可以当这两名员工的翻译(即有一名员工会这两名员工会的语言中的各一种)。
问每位员工所需要学习的语言数的和为多少。
题目分析:
我们可以对能够交流的员工建图,然后不难发现以下性质:
- 若 \(A\) 可以和 \(B\) 交流,则 \(B\) 也可以和 \(A\) 交流(即无向性)。
- 若 \(A\) 可以和 \(B\) 交流,\(B\) 可以和 \(C\) 交流,则 \(A\) 也可以和 \(C\) 交流(即传递性)。
所以,此时的问题就变成了给定一张无向图,问加几条边能够使其成为一张连通图。
可能有更好的做法,但我的做法如下:
- 若该点表的员工一种语言也不会,则 \(cnt\) 加一。
- 若该点没有被访问过,且该点表示的员工至少会一种语言,则 \(cnt\) 加一,然后以该点为起点进行 \(\operatorname{dfs}\)。
- 若该点被访问过,则跳过。
此时答案是 \(cnt - 1\)。
注意:若没有员工会语言,则此时的答案是 \(cnt\) 而不是 \(cnt-1\),因为每一名员工都要学一种语言才能交流。
综上,时间复杂度 \(O(n \times m)\),主要取决于建图部分的时间复杂度。
代码实现:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define TIME_LIMIT (time_t)1e3
#define dbg(x) cerr<<#x<<": "<<x<<endl;
#define MAX_SIZE (int)2.1e4
vector <int> hashtable[MAX_SIZE];
unordered_map <int, bool> edges;
int head[MAX_SIZE];
int ver[MAX_SIZE];
int Next[MAX_SIZE];
int tot = 0;
void add(int u,int v){
ver[++tot] = v;
Next[tot] = head[u];
head[u] = tot;
}
bitset<MAX_SIZE>vis;
bitset<MAX_SIZE>pass;
void dfs(int step, int u, int fa){
assert(step<=114);
vis[u] = 1;
for(int i=head[u];i;i=Next[i]){
int v = ver[i];
if(v==fa)
continue;
if(v==u)
continue;
if(!vis[v])
dfs(step+1,v,u);
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef LOCAL
#undef cout
#undef cin
ifstream cin("in.in");
ofstream cout("out.out");
assert(cin.is_open());
assert(cout.is_open());
freopen("in.in","r",stdin);
freopen("out.out","w",stdin);
time_t cs = clock();
#endif
//========================================
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
int k;
cin>>k;
for(int j=1;j<=k;j++){
int lang;
cin>>lang;
hashtable[lang].push_back(i);
}
}
for(int i=1;i<=m;i++){
auto &vec = hashtable[i];
if(vec.empty())
continue;
int u = vec[vec.size()-1];
pass[u] = 1;
vec.pop_back();
for(auto v:vec){
if(!edges[min(u,v)*100+max(v,u)]){
add(u,v);
add(v,u);
pass[v] = 1;
edges[min(u,v)*100+max(v,u)] = 1;
}
}
}
int cnt = 0;
for(int i=1;i<=n;i++) {
if(!vis[i]&&pass[i]){
dfs(1,i,i);
++cnt;
}
}
int nothing = 0;
for(int i=1;i<=n;i++)
if(!pass[i])
++nothing;
if(nothing==n)
cout<<nothing;
else
cout<<nothing+cnt-1;
//========================================
#ifdef LOCAL
cin.close();
cout.close();
time_t ce = clock();
cerr<< "Used Time: " << ce-cs << " ms."<<endl;
if(TIME_LIMIT<ce-cs)
cerr<< "Warning!! Time exceeded limit!!"<<endl;
#endif
return 0;
}
标签:cnt,语言,int,题解,tot,员工,交流,CF277A
From: https://www.cnblogs.com/larry76/p/17127360.html