我也慢慢改成了纯c代码的习惯了,原因是前些时间提交做了对比,c和c++的输入输出的差异,导致时间竟能差异150ms以上,呵呵,以前都没注意到
题意大致上是: 一群牛将被在一个特定路径构成的农场上迁移,每两块农场之间都至少有一条通道,这些牛要求每两块路径至少要有两条通道,求最少需要修建多少条路才能满足要求
思路:每两块农场之间至少有两条通道,也就是说要求添加若干边,将整个图变成一双连通图,需要添加的边的数量和桥的数量有关,图是连通的,因此可以通过查找桥,提取图中的双连通分量,将每一个双连通分量缩成一个点,于是整个连通图,就变成了一个树形图,这时,只需要统计图中度为1的点数量count,因为只要将图中每两个点不重复的添加边,添加(count+1)/2条边就可以了
需要注意的是: 题中说明了可能会有平行边,因此在查找桥的时候,用子结点的深度更新当前节点的最远祖先信息要特殊处理,因为这里可能会有多个子结点为父节点
#include <stdio.h>
#include <memory.h>
#define init(a) memset(a,0,sizeof(a))
#define MIN(a,b) ((a)<(b)?(a):(b))
#define N 5001
struct Edge
{
int dest;
Edge *next;
};
Edge *E[N],mempool[4*N];
int n,m,memh,bridgen,partn;
int root[N],used[N],anc[N],deep[N],part[N],degree[N],bridge[N][2];
void readData();
void addEdge(int u,int v);
void merge(int u,int v);
int findSet(int s);
void dfs(int ,int ,int);
void connex();
int work();
int main()
{
while (scanf("%d%d",&n,&m)!=EOF)
{
readData();
connex();
printf("%d/n",work());
}
return 0;
}
void connex()
{
int i,j;
for (i=1;i<=n;i++)
root[i]=i;
init(used);
bridgen=0;
for (i=1;i<=n;i++)
if (!used[i])
dfs(i,0,1);
init(part);
partn=0;
for (i=1;i<=n;i++)
{
j=findSet(i);
if (!part[j])
part[j]=++partn;
part[i]=part[j];
}
}
int work()
{
int i,j,k;
init(degree);
for (k=1;k<=bridgen;k++)
{
i=bridge[k][0];
j=bridge[k][1];
degree[part[i]]++;
degree[part[j]]++;
}
int count=0;
for (i=1;i<=partn;i++)
if (degree[i]==1)
count++;
return (count+1)/2;
}
void dfs(int i,int father,int dth)
{
anc[i]=deep[i]=dth;
used[i]=1;
Edge *L;
int j,repeat=0;
for (L=E[i];L!=NULL;L=L->next)
{
j=L->dest;
if (j==father)
repeat++;
if ((j!=father||repeat!=1)&&used[j]==1)
anc[i]=MIN(anc[i],deep[j]);
if (!used[j])
{
dfs(j,i,dth+1);
anc[i]=MIN(anc[i],anc[j]);
if (anc[j]<=deep[i])
merge(i,j);
else
{
bridge[++bridgen][0]=i;
bridge[bridgen][1]=j;
}
}
}
used[i]=2;
}
void merge(int i,int j)
{
int ri=findSet(i);
int rj=findSet(j);
if (ri!=rj)
root[ri]=rj;
}
int findSet(int i)
{
int j,t;
for (j=i;root[j]!=j;j=root[j]);
while (root[i]!=i)
{
t=root[i];
root[i]=j;
i=t;
}
return j;
}
void addEdge(int u,int v)
{
Edge *L=&mempool[memh++];
L->dest=v;
L->next=E[u];
E[u]=L;
}
void readData()
{
int i,u,v;
init(E);
for (memh=i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
addEdge(u,v);
addEdge(v,u);
}
}