POJ 3352 Road Construction解题报告

题目大意很简单:给定一个双向连通的公路网,当某些公路路段检修的时候可能会由于该段公路不通,可能会使某些旅游点之间无法通行,求至少新建多少条公路,使得任意对一段公路进行检修的时候,所有的旅游景点之间仍然畅通;

分析:检修某一路段导致公路网不畅通的原因必然是该段公路在图中是一桥,因此,完全畅通的方法就是,家最若干条边,使图中不存在桥。先找出所有的桥,将双连通分量进行缩点,得到一个树形图,将所有的叶子结点和根节点依次新加边链接起来,于是新加边的条数即是(度为1的点数目+1)/2,.考虑到题目只要求求度为1的点数目,因此可以部分缩点,利用并查集,保存每个桥边的顶点,统计每个顶点在并查集中的代表元的度数即可

 

#include<stdio.h>
#include<memory.h>

#define N 1000
#define init(a) memset(a,0,sizeof(a))
#define min(a,b) ((a)<(b)?(a):(b))

struct Edge
{
 int dest;
 Edge *next;
};
Edge *E[N+1],mempool[N*2];
int anc[N+1],deep[N+1],used[N+1],root[N+1],bridge[N+1][2];
int n,m,memh,bridge_n;
int part[N+1],part_n,d[N+1];
void addEdge(int u,int v)
{
 Edge *L=&mempool[memh++];
 L->dest=v;
 L->next=E[u];
 E[u]=L;
}

void readData()
{
 int i,j;
 init(E),memh=0;
 scanf("%d%d",&n,&m);
 while(m--)
 {
  scanf("%d%d",&i,&j);
  addEdge(i,j);
  addEdge(j,i);
 }
}

void make_set()
{
 for(int i=1;i<=n;i++)
  root[i]=i;
}

int find_set(int s)
{
 int r,t=s;
 while(t!=root[t])
  t=root[t];
 while(s!=t)
 {
  r=root[s];
  root[s]=t;
  s=r;
 }
 return t;
}

void union_set(int u,int v)
{
 int p1=find_set(u);
 int p2=find_set(v);
 if(p1!=p2)
  root[p2]=p1;
}

void dfs_con(int s,int pre,int d)
{
 anc[s]=deep[s]=d;
 used[s]=1;
 for(Edge *L=E[s];L;L=L->next)
 {
  int j=L->dest;
  if(j!=pre&&used[j]==1)
  anc[s]=min(anc[s],deep[j]);
  if(!used[j])
  {
  dfs_con(j,s,d+1);
  anc[s]=min(anc[s],anc[j]);
  if(anc[j]<=deep[s])
  union_set(j,s);
  else
  {
  bridge[++bridge_n][0]=s;
  bridge[bridge_n][1]=j;
  }
  }
 }
 used[s]=2;
}

void connex()
{
 int i,j;
 init(used);
 make_set();
 bridge_n=0;
 for(i=1;i<=n;i++)
  if(!used[i])
  dfs_con(i,0,1);
}

int work()
{
 int i,j,count=0;
 init(d);
 for(i=1;i<=bridge_n;i++)
 {
  j=find_set(bridge[i][0]);
  d[j]++;
  j=find_set(bridge[i][1]);
  d[j]++;
 }
 for(i=1;i<=n;i++)
  if(d[i]==1)
  count++;
 return (count+1)/2;
}

int main()
{
 readData();
 connex();
 printf("%d/n",work());
 return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值