您的位置:首页 > 其它

HDU 5483 (最小生成树 + 求无向图割边)

2015-09-30 00:22 351 查看
题意:给定一个无向图,求必然出现在其MST上的边的数量。

考虑Kruskal求解MST的过程,显然只有在出现边权相等的情况下,得到的MST不唯一。

那么接下来就是确定在每一组边权相等的边集中,哪些边是必然会出现在MST上的。

我们按照边权从小到大的顺序枚举每一组边权相等的边,然后以每一个连通分量为节点重新建图,并将这些边添加进去。

然后我们的目标便是求得该图的任意一个生成树。显然一条边必然出现在生成树的充要条件是该边为该无向图的割边,所以只要求一遍割边即可。

#define N 3072
#define PII pair<int,int>
#include <bits/stdc++.h>
using namespace std;

vector<int> g
;
vector<PII> edge,v
;
int T,n,x,cnt,res,p
,dfn
,low
;

int find(int x)
{
return p[x]==x?p[x]:p[x]=find(p[x]);
}

void dfs(int u,int fa)
{
dfn[u]=low[u]=++cnt;
for(int i=0;i<g[u].size();i++)
{
int id=g[u][i];
if(id!=fa)
{
int v=edge[id].first==u?edge[id].second:edge[id].first;
if(!dfn[v])
{
dfs(v,id),low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]) res++;
}
else
low[u]=min(low[u],dfn[v]);
}
}
}

int main()
{
for(cin>>T;T--;)
{
cin>>n;
for(int i=1;i<N;i++)
v[i].clear(),p[i]=i;

for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
scanf("%d",&x),v[x].push_back(PII(i,j));

res=0;
for(int i=1;i<N;i++)
{
edge.clear();
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));

for(int j=1;j<=n;j++)
g[j].clear();
for(int j=0;j<v[i].size();j++)
{
int x=find(v[i][j].first),y=find(v[i][j].second);
if(x!=y)
edge.push_back(PII(x,y)),g[x].push_back(edge.size()-1),g[y].push_back(edge.size()-1);
}

for(int j=1;j<=n;j++)
if(!dfn[j]) cnt=0,dfs(j,-1);
for(int j=0;j<v[i].size();j++)
{
int x=find(v[i][j].first),y=find(v[i][j].second);
if(x!=y) p[x]=y;
}
}
cout<<res<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: