HDU4612 Warm up(割邊+樹的直徑)

Warm up

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 7504    Accepted Submission(s): 1747


Problem Description
  N planets are connected by M bidirectional channels that allow instant transportation. It's always possible to travel between any two planets through these channels.
  If we can isolate some planets from others by breaking only one channel , the channel is called a bridge of the transportation system.
People don't like to be isolated. So they ask what's the minimal number of bridges they can have if they decide to build a new channel.
  Note that there could be more than one channel between two planets.
 

Input
  The input contains multiple cases.
  Each case starts with two positive integers N and M , indicating the number of planets and the number of channels.
  (2<=N<=200000, 1<=M<=1000000)
  Next M lines each contains two positive integers A and B, indicating a channel between planet A and B in the system. Planets are numbered by 1..N.
  A line with two integers '0' terminates the input.
 

Output
  For each case, output the minimal number of bridges after building a new channel in a line.
 

Sample Input
4 4 1 2 1 3 1 4 2 3 0 0
 

Sample Output
0


題意:給出一張無向圖,問添加一條邊,最少還剩多少條割邊

首先縮點,此時每個塊與塊之間相連的只有橋,這樣方便處理問題

要找最小還剩多少條割邊,即找最大可以刪去多少條割邊,什麼情況下最優,找一條最長的割邊鏈,讓他們首尾相連,這不正是樹的直徑嗎?

求出原有的割邊數量,減去樹的直徑

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#define inf 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=200005;
int low[N],dfn[N],dfs_num,vis[N];//tarjan
int tot,first[N];//鄰接表
int col_num,top,block[N];//染色
int st[N];//染色與點雙聯通
int dis[N];
struct edge
{
    int v,next;
} e[N*20];
vector<int>mp[N];
void init(int n)
{
    mem(first,-1);
    tot=0,col_num=0,dfs_num=0;

}
void add(int u,int v)
{
    e[tot].v=v;
    e[tot].next=first[u];
    first[u]=tot++;
}
void dyeing(int u)//染色
{
    int v;
    if(low[u]==dfn[u])
    {
        ++col_num;
        do
        {
            v=st[--top];
            block[v]=col_num;
            vis[v]=0;
        }
        while(v!=u);
    }
}
void dfs(int u,int fa)
{
    int flag=0;
    low[u]=dfn[u]=++dfs_num;
    vis[u]=1;
    st[top++]=u;
    for(int i=first[u]; ~i; i=e[i].next)
    {
        int v=e[i].v;
       if(flag==0&&v==fa)
       {
           flag=1;
           continue;
       }
        if(!dfn[v])
        {
            dfs(v,u);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v])
            low[u]=min(low[u],dfn[v]);
    }
    dyeing(u);//染色
}
void diameter(int s,int fa,int len)//求樹的端點
{
    vis[s]=1;
    dis[s]=len;
    for(int i=0;i<mp[s].size();i++)
    {
        int v=mp[s][i];
        if(!vis[v])
            (v,s,len+1);
    }
}

int main()
{
    int n,m,x,y;
    while(scanf("%d%d",&n,&m)&&n+m)
    {
        init(n);
        mem(dfn,0);
        mem(low,0);
        mem(vis,0);
        mem(block,0);
        mem(st,0);
        for(int i=1;i<=n;i++)
        mp[i].clear();
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        for(int i=1; i<=n; i++)
        {
            if(!dfn[i])
                dfs(i,-1);
        }
        for(int i=1; i<=n; i++)
        {
            for(int j=first[i]; ~j; j=e[j].next)
            {
                int v=e[j].v;
                if(block[i]==block[v])continue;
                mp[block[i]].push_back(block[v]);
            }
        }
        mem(dis,0);
        mem(vis,0);
        //以任意一點爲起點,求直徑的一個端點
        diameter(1,-1,1);
        int maxx=0,pos=-1;
        for(int i=1; i<=col_num; i++)
        {
            if(maxx<dis[i])
            {
                maxx=dis[i];
                pos=i;
            }
        }
        //以端點爲起點,求另一個端點
        mem(dis,0);
        mem(vis,0);
        diameter(pos,-1,1);
        maxx=0;
        for(int i=1;i<=col_num;i++)
         maxx=max(dis[i],maxx);
         printf("%d\n",col_num-maxx);
    }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章