Arab Collegiate Programming Contest 2015 K Road Network 【树的直径】

Descripion

After a fierce battle with his opponent, Bruce Wayne finally won the elections and became the mayorof Gotham. Like every other politician, he had an agenda with lots of projects for the sake of Gotham'sprosperity, but he was met with the same problem, lack of fund.

He decided to tackle the problem from a different perspective; he will allow companies to buyroads in the city (roads in the city are undirected). The city will get the money needed for the projectsand the companies can use the roads for advertisements (or so he thought). 

After the deal was done, the companies were more cunning than he expected. They started tothreaten that they will block exactly one road in the city and prevent people from getting to their work,in the hope that people will revolt against Mayor Wayne. The problem was that the city is designed as atree of connected zones, where there is only one unique path between any two zones. Hence, blocking aroad means that some zones are not reachable from others anymore. 

Mayor Wayne discussed the problem with his council and identified what they called vulnerableroads. A road is vulnerable if blocking it can disconnect two zones from each other. Mayor Wayne wantsto prevent this from happening by building more roads but his budget could afford building only oneextra road. Can you help him figure out which road he should build, such that he minimizes the numberof vulnerable roads?

Input

Your program will be tested on one or more test cases. The first line of the input will be a single integerT, the number of test cases (1 ≤ T ≤ 100) followed by T test cases. The first line of each test case willcontain one integer N, the number of zones in the city (1 ≤ N ≤ 10, 000). The following N - 1 lines willeach contain a pair of integers x and y separated by a single space (1 ≤ x, y ≤ N) which means that zonex is connected to zone y. It's guaranteed that the edges will form a tree.  

Output

For each test case, print a single line containing an integer, the minimum number of vulnerable roads inthe city after building the new road. 

样例输入

2
3
1 2
1 3
4
1 2
2 3
2 4

样例输出

0
1

题目大意:

给定一棵树,要求增加一条边,使得图中的割边最少。

分析:

在不加边之前,树中所有的边都是割边。

在树中加上一条边,一定会构成一个环,而环中任意一条边都不会是割边,不在环中的边则仍然是割边。

那么要使最终的割边最少, 就要使得形成的环最大。

那么就只要找到树的直径,连接直径的两端就会形成最大的环。

所以只要求树的直径就行。

具体解释见代码。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <queue>
#define INF 0x3f3f3f3f
#define mst(a,num) memset(a,num,sizeof a)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
const ll mod = 1e9 + 7;
const int maxn = 100000 + 5;

int head[maxn];
int vis[maxn];//在BFS中,标记当前节点是否已经用过 
int dis[maxn];//记录最长距离(即节点的深度)  
 
int n,m,ans;
 
int sum;//记录最长路径的长度 
int lst;//记录最长路径的终点节点 
 
struct node{

    int u,v,w;
    int next;

}edge[maxn];
 
void add(int u,int v,int w){//向邻接表中加边 

    edge[ans].u=u;
    edge[ans].v=v;
    edge[ans].w=w;
    edge[ans].next=head[u];
    head[u]=ans++;
}
 
void getmap(){
 
    int i,j;
    int a,b,c;
    ans=0;
    memset(head,-1,sizeof(head));
 
    while(m--){
 
        scanf("%d%d",&a,&b);
        add(a,b,1);
        add(b,a,1);
    }
}
 
void bfs(int beg){
 
    queue<int> q;
    memset(dis,0,sizeof(dis));
    memset(vis,0,sizeof(vis));
    int i,j;
    while(!q.empty())
        q.pop();
    lst=beg;//终点初始化为起点 
    sum=0;
    vis[beg]=1;
    q.push(beg);
    int top;
    while(!q.empty()){
        top=q.front();
        q.pop();
        for(i=head[top];i!=-1;i=edge[i].next){
            if(!vis[edge[i].v]){
                dis[edge[i].v]=dis[top]+edge[i].w;//更新节点深度 
                vis[edge[i].v]=1;
                q.push(edge[i].v);
                if(sum<dis[edge[i].v]){//用该节点的深度去更新最长路径的值 
                    sum=dis[edge[i].v];
                    lst=edge[i].v;
                } 
            }
        }
    }
}

int main() {
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        m=n-1;
        getmap();

        //两次bfs找到树的直径
        bfs(1);
        bfs(lst);
        printf("%d\n",n-1-sum);//树的直径以外的边都是割边
    }
    return 0;
}
发布了30 篇原创文章 · 获赞 5 · 访问量 900

猜你喜欢

转载自blog.csdn.net/qq_42840665/article/details/104977853
今日推荐