1. 程式人生 > >[dfs][bfs] Jzoj P5806 簡單的操作

[dfs][bfs] Jzoj P5806 簡單的操作

style des script 大於 ast d+ eof pri 是否

Description


從前有個包含n個點,m條邊,無自環和重邊的無向圖。
對於兩個沒有直接連邊的點u;v,你可以將它們合並。具體來說,你可以刪除u;v及所有以它們作為端點的邊,然後加入一個新點x,將它與所有在原圖中與u或v有直接連邊的點連邊。
你需要判斷是否能通過若幹次合並操作使得原圖成為一條鏈,如果能,你還需要求出這條鏈的最大長度

Input

從文件merge.in中讀入數據。
第一行兩個正整數n;m,表示圖的點數和邊數。
接下來m行,每行兩個正整數u;v,表示u和v之間有一條無向邊

Output

輸出到文件merge.out中。
如果能通過若幹次合並操作使得原圖成為一條鏈,輸出鏈的最大長度,否則輸出-1

Sample Input

【樣例1輸入】
5 4
1 2
2 3
3 4
3 5
【樣例2輸入】
4 6
1 2
2 3
1 3
3 4
2 4
1 4

 

Sample Output

【樣例1輸出】
3
【樣例2輸出】
-1
 

Data Constraint

技術分享圖片對於30%的數據,技術分享圖片
對於70%的數據,技術分享圖片
對於100%的數據,技術分享圖片

題解

  • 首先,我們可以發現,對於一個三元環是不可以合並的,因為合並只能選兩個沒有直接相連的點
  • 對於一個長度大於3的奇環,最後合並一定也會合並出一個三元環
  • 那這個圖,就是一個二分圖
  • 先將二分圖中的全部聯通分量和每個點屬於哪個聯通分量求出來
  • 這個可以用dfs實現
  • 對於每一個連通分量都構造了一條鏈
  • 而對於任意兩條鏈
  • 顯然可以通過一 次合並操作將它們並成一條,長度為它們的長度之和
  • 因此,答案就是所有連通塊的直徑之和
  • 可以用bfs實現

代碼

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cmath>
 5 using namespace std;
 6 struct
edge { int to,from; }e[100005*2]; 7 int n,m,cnt,tot,bz[1005],ans[1005],last[1005],state[1005][2],visit[1005],head,tail,mx; 8 bool boo; 9 void insert(int x,int y) { e[++cnt].to=y; e[cnt].from=last[x]; last[x]=cnt; } 10 int abs(int x) { return x<0?-x:x; } 11 void dfs(int x,int k) 12 { 13 if (boo==1) return; 14 bz[x]=k; 15 for (int i=last[x];i;i=e[i].from) 16 { 17 if (boo==1) return; 18 if (bz[e[i].to]==k) 19 { 20 boo=1; 21 return; 22 } 23 if (bz[e[i].to]==-k) continue; 24 dfs(e[i].to,-k); 25 } 26 } 27 int bfs(int x) 28 { 29 memset(visit,0,sizeof(visit)); 30 memset(state,0,sizeof(state)); 31 head=0; tail=1; state[1][1]=x; visit[x]=1; 32 int r=0; 33 while (head<tail) 34 { 35 head++; 36 int u=state[head][1]; 37 r=max(r,state[head][2]); 38 for (int i=last[u];i;i=e[i].from) 39 if (visit[e[i].to]==0) 40 { 41 visit[e[i].to]=1; 42 tail++; 43 state[tail][1]=e[i].to; state[tail][2]=state[head][2]+1; 44 } 45 } 46 return r; 47 } 48 int main() 49 { 50 freopen("merge.in","r",stdin); 51 freopen("merge.out","w",stdout); 52 scanf("%d%d",&n,&m); 53 for (int i=1;i<=m;i++) 54 { 55 int u,v; 56 scanf("%d%d",&u,&v); 57 insert(u,v); insert(v,u); 58 } 59 for (int i=1;i<=n;i++) 60 { 61 if (!bz[i]) dfs(i,++tot); 62 if (boo) 63 { 64 printf("-1\n"); 65 return 0; 66 } 67 } 68 for (int i=1;i<=n;i++) ans[abs(bz[i])]=max(ans[abs(bz[i])],bfs(i)); 69 for (int i=1;i<=tot;i++) mx+=ans[i]; 70 printf("%d",mx); 71 return 0; 72 }

[dfs][bfs] Jzoj P5806 簡單的操作