pku3352 Road Construction
#include <iostream>
using namespace std;
#define MAXN 1001
#define min(a,b) (a<b?a:b)
int p[MAXN],n,ecnt,m,dfn[MAXN],lowlink[MAXN],sign,deg[MAXN],color[MAXN],totcol;
struct Edge{
int v,next;
}edg[10*MAXN];
void init(){
ecnt=0;
sign=0;
memset(p,-1,sizeof(p));
memset(dfn,-1,sizeof(dfn));
memset(deg,0,sizeof(deg));
memset(color,0,sizeof(color));
totcol=0;
}
void dfs(int pre,int u){
int i,v;
dfn[u]=lowlink[u]=++sign;
for(i=p[u];i!=-1;i=edg[i].next){
v=edg[i].v;
if(dfn[v]!=-1){
if(v!=pre)
lowlink[u]=min(lowlink[u],dfn[v]);
}
else{
dfs(u,v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}
}
}
void flood(int u){
int i,v;
for(i=p[u];i!=-1;i=edg[i].next){
v=edg[i].v;
if(!color[v]){
if(dfn[u]<lowlink[v])
color[v]=++totcol;
else
color[v]=color[u];
flood(v);
}
}
}
int solve(){
int i,u,v;
dfs(-1,1);
color[1]=++totcol;
flood(1);//着色区分图内各分量
for(u=1;u<=n;u++){
for(i=p[u];i!=-1;i=edg[i].next){
v=edg[i].v;
if(color[u]!=color[v])
deg[color[u]]++;//由于图是由两条相反的有向边表示无向边的,计算某结点的度只需计算其出度
}
}
int ans=0;
for(i=1;i<=totcol;i++)
if(deg[i]==1)//叶子的度为1
ans++;
return ans;
}
int main(){
int i,u,v;
while(scanf("%d%d",&n,&m)!=EOF){
init();
for(i=0;i<m;i++){
scanf("%d%d",&u,&v);
edg[ecnt].next=p[u];
edg[ecnt].v=v;
p[u]=ecnt++;
edg[ecnt].next=p[v];
edg[ecnt].v=u;
p[v]=ecnt++;
}
printf("%d\n",(solve()+1)/2);//每添一条边,就选择树中的两个叶子结点,将它们连起来,于是最少的添边数目就是(叶子结点个数+1)/2
}
return 0;
}
using namespace std;
#define MAXN 1001
#define min(a,b) (a<b?a:b)
int p[MAXN],n,ecnt,m,dfn[MAXN],lowlink[MAXN],sign,deg[MAXN],color[MAXN],totcol;
struct Edge{
int v,next;
}edg[10*MAXN];
void init(){
ecnt=0;
sign=0;
memset(p,-1,sizeof(p));
memset(dfn,-1,sizeof(dfn));
memset(deg,0,sizeof(deg));
memset(color,0,sizeof(color));
totcol=0;
}
void dfs(int pre,int u){
int i,v;
dfn[u]=lowlink[u]=++sign;
for(i=p[u];i!=-1;i=edg[i].next){
v=edg[i].v;
if(dfn[v]!=-1){
if(v!=pre)
lowlink[u]=min(lowlink[u],dfn[v]);
}
else{
dfs(u,v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}
}
}
void flood(int u){
int i,v;
for(i=p[u];i!=-1;i=edg[i].next){
v=edg[i].v;
if(!color[v]){
if(dfn[u]<lowlink[v])
color[v]=++totcol;
else
color[v]=color[u];
flood(v);
}
}
}
int solve(){
int i,u,v;
dfs(-1,1);
color[1]=++totcol;
flood(1);//着色区分图内各分量
for(u=1;u<=n;u++){
for(i=p[u];i!=-1;i=edg[i].next){
v=edg[i].v;
if(color[u]!=color[v])
deg[color[u]]++;//由于图是由两条相反的有向边表示无向边的,计算某结点的度只需计算其出度
}
}
int ans=0;
for(i=1;i<=totcol;i++)
if(deg[i]==1)//叶子的度为1
ans++;
return ans;
}
int main(){
int i,u,v;
while(scanf("%d%d",&n,&m)!=EOF){
init();
for(i=0;i<m;i++){
scanf("%d%d",&u,&v);
edg[ecnt].next=p[u];
edg[ecnt].v=v;
p[u]=ecnt++;
edg[ecnt].next=p[v];
edg[ecnt].v=u;
p[v]=ecnt++;
}
printf("%d\n",(solve()+1)/2);//每添一条边,就选择树中的两个叶子结点,将它们连起来,于是最少的添边数目就是(叶子结点个数+1)/2
}
return 0;
}