CodeForces 51F Caterpillar

time limit per test 2 seconds
memory limit per test 256 megabytes
input standard input
output standard output

An undirected graph is called a caterpillar if it is a connected graph without cycles and it has such a path p that any vertex is located at a distance of at most 1 from the path p. The caterpillar can contain loops (edges from a vertex to itself) but cannot contain multiple (parallel) edges.

The picture contains an example of a caterpillar:

CodeForces 51F Caterpillar

You are given an undirected graph G. You are allowed to do a merging operations, each such operation merges two vertices into one vertex. For that two any vertices a and b (a ≠ b) are chosen. These verteces are deleted together with their edges (which are incident to at least one of the vertices a or b) but a new vertex w is added together with edges (x, w) for each edge (a, w) and/or (b, w). If there was the edge (a, b) it transforms to the loop (w, w). The resulting graph (after the merging operation) may contain multiple (parallel) edges between pairs of vertices and loops. Let us note that this operation decreases the number of vertices of graph by 1 but leaves the number of edges in the graph unchanged.

The merging operation can be informally described as a unity of two vertices of the graph into one with the natural transformation of the graph edges.

You may apply this operation consecutively and make the given graph to be a caterpillar. Write a program that will print the minimal number of merging operations required to make the given graph a caterpillar.

Input

The first line contains a pair of integers nm (1 ≤ n ≤ 2000;0 ≤ m ≤ 105), where n represents the number of vertices in the graph andm is the number of edges in it. Then the following m lines contain edge descriptions, one edge description per line. Every line contains a pair of integers ai, bi (1 ≤ ai, bi ≤ n;ai ≠ bi), ai, bi which represent the indices of the vertices connected by the edge. The vertices are numbered from 1 to n. In the given graph it will be no more than one edge between any pair of vertices. The given graph is not necessarily connected.

Output

Print the minimal required number of operations.

Examples
input
4 4
1 2
2 3
3 4
4 2
output
2
input
6 3
1 2
3 4
5 6
output
2
input
7 6
1 2
2 3
1 4
4 5
1 6
6 7
output
1

缩点

  目标状态是一棵树,可以有自环,不能有重边。tarjan缩点后,原图形成一片森林,对于每一棵树,它最多可以保留点数res=直径上的点数+其他叶子结点树。处理森林中的每一棵树,ans=total-res

_____

  刚开始没察觉到有森林,按照树处理,WA飞

  之后因为缩点后重边加多了,T飞

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int mx[]={,,,-,};
const int my[]={,,,,-};
const int mxn=;
int read(){
int x=,f=;char ch=getchar();
while(ch<'' || ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>='' && ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
struct edge{
int v,nxt;
}e[];
int hd[mxn],mct=;
void add_edge(int u,int v){
e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;return;
}
int mp[mxn][mxn];
int n,m;
int dtime=;
int low[mxn],dfn[mxn];
int belone[mxn],cnt;
int st[mxn],top=;
void tarjan(int u,int fa){
dfn[u]=low[u]=++dtime;
st[++top]=u;
for(int i=hd[u];i;i=e[i].nxt){
int v=e[i].v;
if(v==fa)continue;
if(!dfn[v]){
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
else low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
cnt++;
int v=;
do{
v=st[top--];
belone[v]=cnt;
}while(v!=u);
}
return;
}
vector<int>eg[mxn];
int dis[mxn];
bool vis[mxn];int kct=;
int tg=;
void DFS(int u,int fa){
vis[u]=;
dis[u]=dis[fa]+;
if(dis[u]>dis[tg])tg=u;
for(int i=;i<eg[u].size();i++){
int v=eg[u][i];
if(v==fa)continue;
DFS(v,u);
}
return;
}
int pos1,pos2;
int outd[mxn];
int solve(){
if(cnt==)return n-;
int i,j;
for(i=;i<=n;i++){
for(j=hd[i];j;j=e[j].nxt){
int v=e[j].v;
if(mp[belone[i]][belone[v]])continue;
if(belone[i]!=belone[v]){
eg[belone[i]].push_back(belone[v]);
mp[belone[i]][belone[v]]=;//防止加重边
outd[belone[i]]++;
}
}
}
int res=;
for(i=;i<=cnt;i++)if(outd[i]==) res++;//叶子节点数
for(i=;i<=cnt;i++){
if(vis[i])continue;
kct++;//联通块计数
//
tg=;
DFS(i,);
pos1=tg;
tg=;
DFS(pos1,);
pos2=tg;
//求直径
if(dis[pos2]<)res++;
else res+=dis[pos2]-;
}
return n-res+kct-;
}
int main()
{
n=read();m=read();
int i,j,u,v;
for(i=;i<=m;i++){
u=read();v=read();
add_edge(u,v);
add_edge(v,u);
}
for(i=;i<=n;i++)
if(!dfn[i])tarjan(i,);
int ans=solve();
printf("%d\n",ans);
return ;
}
上一篇:团队作业8——第二次项目冲刺(Beta阶段)--5.25 5th day


下一篇:C++的头文件和实现文件分别写什么