Newcoder 40 C.珂朵莉的二分圖(dfs+樹形)
阿新 • • 發佈:2018-12-16
Description
珂朵莉給你一個無向圖
其有個點,條邊
對於每條邊,她想知道刪了這條邊之後這個圖是不是一個二分圖
Input
第一行兩個整數
之後行,每行兩個數表示有一條和之間的無向邊
第個邊的序號即為
output
第一行輸出一個整數,表示有多少邊滿足條件
接下來一行,從小到大輸出這些邊的序號
如果沒有邊滿足條件,只輸出一行一個數,注意不要多輸出換行
Sample Input
4 4 1 2 1 3 2 4 3 4
Sample Output
4 1 2 3 4
Solution
一個圖是二分圖當且僅當該圖無奇環,若想讓該圖成為一個二分圖,必須破掉所有奇環,那麼就要選擇所有奇環交集中的一條邊,注意到一個奇環和一個偶環在刪去一條公共邊後依舊是一個奇環,故不能刪去偶環上的邊
具體做法,首先統計所有自環,如果又有奇環又有自環,顯然不行;如果沒有奇環但是有超過一個自環也不行;如果沒有自環也沒有奇環,刪去任意一條邊都行;如果沒有自環只有奇環,整張圖,維護每個點的深度,如果當前點的一個鄰接點之前被經過,且深度不超過(如果深度超過只能是有重邊,這種偶環不用管,因為這種邊不會出現在奇環的交集中),那麼說明之間構成一個環,且該環是由樹上的這條鏈和當前的邊構成,我們可以在樹上維護一個標記的字首和,標記這一段所有的邊,表示這些邊屬於這個環,注意到可以通過深度差判斷該環是奇環還是偶環,如果是奇環則打上正標記,否則打上負標記,假設共有個奇環,那麼被打上個標記的邊都是合法邊,同時注意,若只有一個奇環,那麼那條非樹邊也是合法邊
Code
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<ctime> using namespace std; const int maxn=1000005; struct node { int v,id,next; }e[2*maxn]; int head[maxn],tot; void add(int u,int v,int id) { e[tot].v=v,e[tot].id=id,e[tot].next=head[u],head[u]=tot++; } int n,m,dep[maxn],num[maxn],vis[maxn],cir,self,not_tree; vector<int>ans; void dfs(int u,int fa) { vis[u]=1; for(int i=head[u];~i;i=e[i].next) { if(i==fa)continue; int v=e[i].v; if(!vis[v]) { dep[v]=dep[u]+1; dfs(v,i^1); num[u]+=num[v]; } else { if(dep[v]>dep[u])continue; if((dep[u]-dep[v]+1)&1)num[u]++,num[v]--,cir++,not_tree=e[i].id; else num[u]--,num[v]++; } } } void dfs1(int u,int fa) { vis[u]=1; if(num[u]==cir)ans.push_back(e[fa].id); for(int i=head[u];~i;i=e[i].next) if(!vis[e[i].v])dfs1(e[i].v,i); } int main() { scanf("%d%d",&n,&m); memset(head,-1,sizeof(head)); tot=0; for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); if(u==v)self++,ans.push_back(i); else add(u,v,i),add(v,u,i); } for(int i=1;i<=n;i++) if(!vis[i]) { dep[i]=1; dfs(i,-1); } if(!cir) { if(self==0) { printf("%d\n",m); for(int i=1;i<=m;i++)printf("%d%c",i,i==m?'\n':' '); } else if(self==1)printf("1\n%d\n",ans[0]); else printf("0\n"); } else { if(self)printf("0\n"); else { memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) if(!vis[i])dfs1(i,-1); if(cir==1)ans.push_back(not_tree); printf("%d\n",ans.size()); sort(ans.begin(),ans.end()); for(int i=0;i<ans.size();i++)printf("%d%c",ans[i],i==ans.size()-1?'\n':' '); } } return 0; }