【CodeForces - 920E】Connected Components? (dsu,补图连通块,STLset+map,bfs 或bitset)
題干:
You are given an undirected graph consisting of?n?vertices and??edges. Instead of giving you the edges that exist in the graph, we give you?m?unordered pairs (x,?y) such that there is no edge between?x?and?y, and if some pair of vertices is not listed in the input, then there is an edge between these vertices.
You have to find the number of connected components in the graph and the size of each component. A connected component is a set of vertices?X?such that for every two vertices from this set there exists at least one path in the graph connecting these vertices, but adding any other vertex to?X?violates this rule.
Input
The first line contains two integers?n?and?m?(1?≤?n?≤?200000,?).
Then?m?lines follow, each containing a pair of integers?x?and?y?(1?≤?x,?y?≤?n,?x?≠?y) denoting that?there is no edge?between?x?and?y. Each pair is listed at most once; (x,?y) and (y,?x) are considered the same (so they are never listed in the same test). If some pair of vertices is not listed in the input, then there?exists?an edge between those vertices.
Output
Firstly print?k?— the number of connected components in this graph.
Then print?k?integers — the sizes of components. You should output these integers in non-descending order.
Example
Input
5 5 1 2 3 4 3 2 4 2 2 5Output
2 1 4題目大意:
無向圖中給定n個頂點,m條不存在的邊(除了這m條邊,其余都存在),求圖的連通分量,及每個連通分量的大小。
解題報告:
官方題解:
別從給定的邊入手,而是直接對所有頂點bfs就可以了,可以證明復(fù)雜度是線性的,頂多加上容器自帶的log。
當(dāng)然, 其實用不到upperbound,因為bfs就是邊刪除邊進(jìn)行的,不會涉及迭代器危機(jī)。但是dfs就比較危險了,下面代碼就有對應(yīng)官方題解的dfs。
AC代碼1:(240ms)
vector維護(hù)當(dāng)前還剩多少點沒有被訪問到(注意巧妙的O1維護(hù)方式,正常的維護(hù)需要On的時間)。map記錄邊的信息
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define F first #define S second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 2e5 + 5; map<int,bool> mp[MAX]; vector<int> vv,ans; int bfs(int x) {int res = 0;queue<int> q;q.push(x);while(q.size()) {int cur = q.front();q.pop();res++; // int up = vv.size();這里不能這樣寫,因為size是動態(tài)的。for(int i = 0; i<(int)vv.size(); i++) {int v = vv[i];if(mp[cur].count(v) == 0) {swap(vv[i],vv.back());//用來實現(xiàn)set的erase操作,減少常數(shù)。 vv.pop_back();//用來實現(xiàn)set的erase操作 i--;q.push(v);}}}return res; } int main() {int n,m;cin>>n>>m;for(int i = 1; i<=n; i++) vv.pb(i);for(int x,y,i = 1; i<=m; i++) {scanf("%d%d",&x,&y);mp[x][y]=1;mp[y][x]=1;}while(!vv.empty()) {int v = vv.back();vv.pop_back();int cnt = bfs(v);ans.push_back(cnt);}sort(ans.begin(),ans.end());printf("%d\n",ans.size());for(int i = 0; i<(int)ans.size(); i++) {printf("%d ",ans[i]);}return 0 ; }?
AC代碼2:
用set維護(hù)未被訪問的點集,bfs中對于每一個點,先一遍操作,同時記錄一個vector,然后再更新到set中(刪除元素),這樣避免了邊操作邊更新所帶來的迭代器的變化,避免了 不好控制 的情況發(fā)生。
?
AC代碼3:
用map<int,set<int> > mp? 來減小內(nèi)存。(實際上也無所謂,直接開2e5個set一樣的)
注意dfs中,用pair來接受一個map,也就是這里ip其實代表的就是一個pair。
這里也掌握一種姿勢:就算是遇到AC代碼2那種? set迭代器的問題的時候,第一可以用AC代碼2那種處理方式,第二可以改用map:如果需要刪除it,那就先將it記錄到tmp中,然后刪除it,然后再upperbound一下就可以了。
AC代碼4:
bitset維護(hù)未訪問的點集。
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #include<bitset> #define F first #define S second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 2e5 + 5; set<int> ss[MAX]; bitset<MAX> bs; int n,m,ans[MAX],tot; void dfs(int x) {bs[x] = 0;ans[tot]++;for(int i = bs._Find_first(); i<bs.size(); i = bs._Find_next(i)) {if(ss[x].count(i) == 0) dfs(i);} } int main() {cin>>n>>m;for(int i = 1; i<=n; i++) bs[i] = 1;for(int u,v,i = 1; i<=m; i++) {scanf("%d%d",&u,&v);ss[u].insert(v);ss[v].insert(u);}for(int i = 1; i<=n; i++) {if(bs[i]) tot++,dfs(i);}printf("%d\n",tot);sort(ans+1,ans+tot+1);for(int i = 1; i<=tot; i++) {printf("%d%c",ans[i],i == tot ? '\n' : ' ');}return 0 ; }貼一個更快的:
AC代碼5:
//別人的代碼 #include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define F first #define S second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 2e5 + 5; set<int>st; vector<int> mp[MAX]; int ans[MAX]; int del[MAX]; int n,m,tot; void Bfs(int x) {tot++;ans[tot]=1;st.erase(x);queue<int>s;s.push(x);while(!s.empty()) {int u=s.front();s.pop();int cnt=0;for(set<int>::iterator it=st.begin(); it!=st.end(); it++) {int to=*it;if(binary_search(mp[u].begin(),mp[u].end(),to) == 0) {s.push(to);ans[tot]++;del[++cnt]=to;}}for(int i=1; i<=cnt; i++)st.erase(del[i]);} } int main() {scanf("%d%d",&n,&m);tot=0;st.clear();for(int i=1; i<=m; i++) {int x,y;scanf("%d%d",&x,&y);mp[x].push_back(y);mp[y].push_back(x);}for(int i=1; i<=n; i++)st.insert(i),sort(mp[i].begin(),mp[i].end());for(int i=1; i<=n; i++) {if(st.count(i))Bfs(i);}printf("%d\n",tot);sort(ans+1,ans+tot+1);for(int i=1; i<=tot; i++) {printf("%d ",ans[i]);} }總結(jié)
以上是生活随笔為你收集整理的【CodeForces - 920E】Connected Components? (dsu,补图连通块,STLset+map,bfs 或bitset)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pvlsvr.exe - pvlsvr是
- 下一篇: qbdagent2002.exe - q