2013 多校第二场 hdu 4612 Warm up

hdu 4612

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4612

题目大意:给你一幅图,问你加一条边,使桥数最小,输出这个最小桥数。

思路:先缩点,那么它就是一棵树,原图的桥数也就是求出来强连通分量的个数-1,再求出树的最长边(点数最多),那么最小的桥数 = 原图的桥数 - 最长边对应的点数。

其实这道题我们比赛的思路已经非常正确了,就是按照上面那么想到的,就是 tarjan()之前只用它做过有向图的缩点,没做过无向图的,当时也一样标记搜过的点去了,一直WA,其实标记搜过的边就好了,还是基本功不够啊。。 = =

另外,原来杭电 STACK_OVERFLOW ,还能手动增加栈的深度的,这个倒是第一次见。 = =

代码如下:

#pragma comment(linker, "/STACK:10240000000000,10240000000000")
#include<cstdio>
#include<cstring>
#include<stack>
#include<vector>
#include<algorithm>
using namespace std;

const int MAX_M = 1000111 ;
const int MAX_N = 200111 ;

struct Edge
{
    int t,next;
} edge[MAX_M<<1];

int tot,head[MAX_N];

void add_edge(int s,int t)
{
    edge[tot].t = t;
    edge[tot].next = head[s];
    head[s] = tot++;
}

stack <int> s;
int dfs_clock,pre[MAX_N],scc_cnt,low_link[MAX_N],sccno[MAX_N];

int vis[MAX_M<<1];

stack <int> ed;

void dfs(int u)
{
	low_link[u]=pre[u]=++dfs_clock;
	s.push(u);
	for(int i = head[u];i!=-1;i=edge[i].next)
	{
	    if(vis[i]) continue;
	    int tmp = (i/2)*2 ;
	    vis[tmp] = 1;vis[tmp+1] = 1;
	    ed.push(tmp);
		int v=edge[i].t;
		if(!pre[v])
		{
			dfs(v);
			low_link[u]=min(low_link[u],low_link[v]);
		}
		else if(!sccno[v])
			low_link[u]=min(low_link[u],pre[v]);
	}
	if(pre[u]==low_link[u])
	{
		scc_cnt++;
		while(!s.empty())
		{
			int x=s.top();
			s.pop();
			sccno[x]=scc_cnt;
			if(x==u) break;
		}
	}
}

int n,m;

void tarjan()
{
	scc_cnt=0;
	dfs_clock=0;
	memset(pre,0,sizeof(pre));
	memset(sccno,0,sizeof(sccno));
	for(int i=1;i<=n;i++)
		if(!sccno[i])
        {
            while(!ed.empty())
            {
                int x = ed.top();
                vis[x]=vis[x+1]=0;
                ed.pop();
            }
			dfs(i);
        }
}

vector <int> G[MAX_N];

void build()
{
    for(int i = 1;i<=scc_cnt;i++)
        G[i].clear();
    for(int i = 1;i<=n;i++)
    {
        for(int e = head[i] ; e!=-1;e = edge[e].next)
        {
            int v = edge[e].t;
            if(sccno[i]!=sccno[v])
            {
                //printf("%d,%d||%d,%d\n",i,sccno[i],v,sccno[v]);
                G[sccno[i]].push_back(sccno[v]);
            }
        }
    }
}

int num[MAX_N],maxx;

void find(int u,int fa)
{
    int m1 =0,m2 = 0;
    num[u]=1;
    for(int i = 0 ; i<G[u].size() ; i++)
    {
        int v = G[u][i];
        if(v==fa) continue;
        find(v,u);
        if(num[v]>m1)
        {
            m2 = m1;
            m1 = num[v];
        }
        else if(num[v]>m2)
        {
            m2 = num[v];
        }
    }
    num[u] = m1+1;
    maxx = max(maxx,m1+m2);
}

int main()
{
    while(scanf("%d%d",&n,&m),n+m)
    {
        int a,b;
        tot=0;
        memset(head,-1,sizeof(head));
        for(int i =0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            add_edge(a,b);
            add_edge(b,a);
        }
        memset(vis,0,sizeof(vis));
        tarjan();
        /*for(int i = 1;i<=n;i++)
            printf("i = %d,sccno = %d\n",i,sccno[i]);*/
        int pre_bridge = scc_cnt-1;
        build();
        maxx = 0;
        find(1,-1);
        //printf("maxx = %d\n",maxx);
        int ans = pre_bridge - maxx;
        printf("%d\n",ans);
    }
    return 0;
}


你可能感兴趣的:(2013 多校第二场 hdu 4612 Warm up)