Description
给定一张n个点m条边的无向图。每次你可以选择两个点u,v,将它们合并为一个点w:对于原先的一条边(u,i)或(v,i),连边(w,i);对于原先的一条边(u,u),(v,v)或(u,v),连边(w,w)。每次缩点后图的点数减小1,边数不变。
求最少需要几次缩点才能使图满足以下条件:(1)不存在重边和简单环,但可以存在自环;(2)存在一条路径使得所有不在路径上的点到它的距离为1。
求最少需要几次缩点才能使图满足以下条件:(1)不存在重边和简单环,但可以存在自环;(2)存在一条路径使得所有不在路径上的点到它的距离为1。
Input
第一行两个整数n,m,接下来m行每行三个整数ui,vi表示一条边。保证不存在重边。
Subtask 1 (10pts):n,m<=10。
Subtask 2 (36pts):n,m<=2000。
Subtask 3 (31pts):给定的图是一棵树。
Subtask 4 (23pts):无特殊限制。
对于全部数据,1<=n,m<=10^5。
Subtask 2 (36pts):n,m<=2000。
Subtask 3 (31pts):给定的图是一棵树。
Subtask 4 (23pts):无特殊限制。
对于全部数据,1<=n,m<=10^5。
Output
输出一行一个整数表示答案。
Sample Input
输入1: 4 4 1 2 2 3 3 4 4 2 输入2: 6 3 1 2 3 4 5 6 输入3: 7 6 1 2 2 3 1 4 4 5 1 6 6 7
Sample Output
输出1: 2 输出2: 2 输出3: 1
Code
#include<bits/stdc++.h> #define eho(X,x) for(int i=X.head[x];i;i=X.net[i]) #define v G1.fall[i] #define V G2.fall[i] #define N 100007 #define pii pair<int,int> using namespace std; int n,col[N],nwa[N],nwb[N],cnt,low[N],dfn[N],cn1,usd[N<<1],op; map<pii,int> ma; struct Graph{ int tot,head[N],net[N<<1],fall[N<<1]; Graph() {tot=1;} void add(int x,int y){ fall[++tot]=y; net[tot]=head[x]; head[x]=tot; } void adds(int x,int y){add(x,y); add(y,x);} }G1,G2; int s[N],tp; int m,x,y,color,ans,us2[N],lef,alg,dis[N],top,he,siz,XX,YY; void tarjan(int x,int f) { dfn[x]=low[x]=++cnt,s[tp++]=x; eho(G1,x) if (v!=f) {if (!dfn[v]) tarjan(v,x);low[x]=min(low[x],low[v]);} if (low[x]==dfn[x]) { color++;do {col[s[--tp]]=color;}while (s[tp]!=x);} } //void tarjan(int x,int f_eg) { // dfn[x]=low[x]=++cnt; // eho(G1,x) { // if (!dfn[v]) { // tarjan(v,i); // low[x]=min(low[x],low[v]); // if (low[v]>low[x]) { // usd[i]=usd[i^1]=1; nwa[++cn1]=G1.fall[i]; nwb[cn1]=G1.fall[i^1]; // } // } else if (i^f_eg^1) low[x]=min(low[x],dfn[v]); // } //} //void dfs(int x,int color) { // col[x]=color; // eho(G1,x) if (!usd[i]&&!col[v]) dfs(v,color); //} void Dfs2(int x,int fa){ int alg=!!fa; us2[x]=1; eho(G2,x) if (V^fa) { alg++; Dfs2(V,x); } lef+=alg<=1; } void Dfs(int x,int fa){ // cerr<<x<<endl; dis[x]=dis[fa]+1; eho(G2,x) if (V^fa) Dfs(V,x); if (dis[x]>dis[top]) top=x; } void work(int x) { lef=0; siz++; Dfs2(x,0); top=0,Dfs(x,0); he=top; top=0,Dfs(he,0); ans+=dis[top]>1?lef+dis[top]-2:1; op+=lef; } signed main () { freopen("merge.in","r",stdin); freopen("merge.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) { scanf("%d%d",&x,&y); G1.adds(x,y); } for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i,0); // for (int i=1;i<=n;i++) { // if (col[i]) continue; // dfs(i,++color); // } int pi=0; // assert(p) // for (int i=1;i<=cn1;i++) { // XX=col[nwa[i]]; YY=col[nwb[i]]; // if (XX>YY) swap(XX,YY); // if (ma.count(pii(XX,YY))) continue; // G2.adds(XX,YY); // ma[pii(XX,YY)]=1; pi++; // } // assert(cn1==pi); for (int j=1;j<=n;j++) eho(G1,j) if (col[j]!=col[v]) G2.add(col[j],col[v]),pi++; // cerr<<pi<<endl; for (int i=1;i<=color;i++) if (!us2[i]) work(i); printf("%d\n",n-ans+siz-1); // cerr<<pi/2+siz<<endl; cerr<<op<<endl; // assert(pi+siz-1==color); return 0; }