920E Connected Components?
阿新 • • 發佈:2018-12-09
這題剛開始想用並查集,因為具體只要點的合併,不需要知道每條邊的權值,所以給了個錯誤答案:
//I(並查集--wa了) #include<stdio.h> #include<string.h> #include<map> #include<algorithm> using namespace std; #define MAXN 200010 map<int,int>R; int vis[MAXN]; int res[MAXN]; int pre[MAXN]; int Find(int x) { if(pre[x]!=x) pre[x]=Find(pre[x]); return pre[x]; } void Union(int x,int y) { int fx=Find(x); int fy=Find(y); if(fx!=fy) pre[fy]=fx; } int main() { int i,j; int n,m; int x,y; int cnt,ans,Count; int fx,fy; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=m;i++) { scanf("%d%d",&x,&y); R[x]=y; R[y]=x; } for(i=1;i<=n;i++) pre[i]=i; for(i=1,cnt=0;i<=n&&cnt<n;i++)//建圖 { cnt++; for(j=i+1;j<=n;j++) { if(R[i]!=j&&R[j]!=i) { fx=pre[i]; fy=pre[j]; if(fx!=fy) { Union(i,j); cnt++; } } } } for(i=1,ans=Count=0;Count<n&&i<=n;i++) { if(!vis[i]) { vis[i]=cnt=1; ans++; Count++; for(j=i+1;j<=n;j++) { fx=pre[i]; fy=pre[j]; if(fx==fy) { cnt++; Count++; vis[j]=1; } } res[ans]=cnt; } } sort(res+1,res+1+ans); printf("%d\n",ans); printf("%d",res[1]); for(i=2;i<=ans;i++) printf(" %d",res[i]); printf("\n"); } return 0; }
仔細分析一下,其實是錯在:
比如1和2可以有邊,2和4可以有邊,雖然最後確實是放在一個集合裡面了,但是這裡卻記錄了2個連通分量。。。。
正確思路網上有很多種,參考了一個大佬的:
講幾個晦澀點:
(1)
這裡加進去的時候不能是標記vis,因為這些點是後來還要用的(畢竟是要算補圖的,和只算原圖的全部都反過來了)
(2)
因為ss是記錄還未找到連通分量的(就在補圖中),而刪去ops的原因是:
也是swap的原因。
請記住,補圖的操作一切都和原圖中的相反,在原圖中是將已經遍歷過的點加入佇列,即:
這些點,但是補圖反過來,就是沒有被遍歷過的點,就是刪除ops中有的點剩下來的點。
還有,最後要swap,因為在for裡面被遍歷到的點,在原圖中是有邊相連的,但是在補圖中反過來,就沒有邊相連了,所以ss要和ops進行swap操作。
還有:
如果沒有這一步,就會MLE,這時將外面的ops或者ss拿到主函式裡面就可以過,
但是更好的方法是加一個清空,因為這個還有一個原因,就是使得
這一步更加容易理解,也更加沒有爭議。
(但是聽說一般set用的是棧記憶體,和放在哪裡沒有關係,那麼調整位置就AC的原因不詳。。。)
程式碼:
//I #include<stdio.h> #include<string.h> #include<algorithm> #include<set> #include<vector> #include<queue> using namespace std; #define MAXN 200001 vector<int>V[MAXN];//儲存每個點的臨邊(原圖中的) set<int>ss,ops;//分別表示在原圖中是獨立的連通分量(即在補圖中是整體連通的)和在原圖中是整體(在補圖中是獨立的) queue<int>q; int ans[MAXN];//記錄每個連通分量中的點的個數 bool vis[MAXN]; int main() { int i,j; int n,m; int u,v; int cnt; scanf("%d%d",&n,&m); memset(V,0,sizeof(V)); for(i=1;i<=m;i++) { scanf("%d%d",&u,&v); V[u].push_back(v); V[v].push_back(u); } for(i=1;i<=n;i++) ss.insert(i);//ss的初始化 cnt=0; memset(vis,0,sizeof(vis)); memset(ans,0,sizeof(ans)); while(!q.empty()) q.pop(); for(i=1;i<=n;i++) { if(vis[i]) continue; q.push(i); cnt++; while(!q.empty()) { u=q.front(); q.pop(); if(vis[u]) continue; vis[u]=true; ans[cnt]++; //set<int>ops; for(j=0;j<V[u].size();j++) { if(!vis[V[u][j]]) ops.insert(V[u][j]); } set<int>::iterator it; for(it=ops.begin();it!=ops.end();it++) ss.erase(*it); for(it=ss.begin();it!=ss.end();it++) q.push(*it); swap(ss,ops);//ss是還未連通的點的集合,因為刪去ops中的點後剩餘的點已經與點u連通了(在一個集合中,但是他們內部可能不是兩兩有直接連邊) ops.clear(); } } sort(ans+1,ans+1+cnt); printf("%d\n",cnt); printf("%d",ans[1]); for(i=2;i<=cnt;i++) printf(" %d",ans[i]); printf("\n"); return 0; }