HDU 3749 Financial Crisis

Financial Crisis

题意:给一个图,包含N ( 3 <= N <= 5000 )个点, M ( 0 <= M <= 10000 )条边 and Q ( 1 <= Q <= 1000 )次查询.查询:两个点是否是点-双连通;

点-双连通:两点至少存在两条"点不重复"的路径;简称双连通(biconnected);

思路:直接调用dfs求割点的算法,其实也是Tarjan发明的,就是在判断出一个割点之后,就把栈S中该双连通分量的所有点(就在栈顶)insert到同一个集合中;

注意:一个点可以属于多个双连通分类,所以bccno数组其实只是一个防止重复insert同一个点,在set中可以除去。并且注意初始化各种数组即序号(这样都TLE几次)

PS:原本使用链式向前星来存储边,可是发现在hd里竟然比直接vector建图还慢。。(一脸茫然);并且开始使用stack<PII> 直接MLE了,可是看别人直接使用库栈。。

 

#include<iostream>
#include<sstream>
#include<cstdio>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<stack>
#include<set>
using namespace std;
#define rep0(i,l,r) for(int i = (l);i < (r);i++)
#define rep1(i,l,r) for(int i = (l);i <= (r);i++)
#define rep_0(i,r,l) for(int i = (r);i > (l);i--)
#define rep_1(i,r,l) for(int i = (r);i >= (l);i--)
#define MS0(a) memset(a,0,sizeof(a))
#define MS1(a) memset(a,-1,sizeof(a))

const int MAXN = 10010;
int low[MAXN],pre[MAXN],dfs_clock,bcc_cnt;
int bccno[MAXN];//看点属于哪个双连通分量;
set<int> bcc[MAXN];//存储每一个双连通分量的点的标号;
typedef pair<int,int> PII;
#define A first
#define B second
#define pb push_back
PII S[MAXN<<1];//存储边,从中取点
vector<int> e[MAXN];
int top;
int dfs(int u,int fa)
{
    int lowu = pre[u] = ++dfs_clock;
    int child = 0;
    rep0(i,0,e[u].size()){
        int v = e[u][i];
        PII e = PII{u,v};
        if(!pre[v]){
            S[++top] = e;
            child++;
            int lowv = dfs(v,u);
            lowu = min(lowu,lowv);//以子节点的low来更新u的low函数;
            if(lowv >= pre[u]){ //表示u-v为桥
                bcc[++bcc_cnt].clear();
                for(;;){
                    PII x = S[top--];
                    if(bccno[x.A] != bcc_cnt){bcc[bcc_cnt].insert(x.A);bccno[x.A] = bcc_cnt;}//就是为了不重复加点
                    if(bccno[x.B] != bcc_cnt){bcc[bcc_cnt].insert(x.B);bccno[x.B] = bcc_cnt;}
                    if(x.A == u && x.B == v) break;//根据加入的顺序知,正好对应;
                }
            }
        }
        else if(v != fa && pre[v] < pre[u]){
            S[++top] = e;
            lowu = min(lowu,pre[v]);
        }
    }
    return low[u] = lowu;
}
int f[MAXN];
int Find(int a)
{
    return a==f[a]?f[a]:f[a]=Find(f[a]);
}
char ans[][15] = {"zero","one","two or more"};
int main()
{
    int N,M,Q,kase = 1;
    while(scanf("%d%d%d",&N,&M,&Q) == 3 && N+M+Q){
        rep0(i,0,N){
            f[i] = i;
            e[i].clear();//直接vector建图
        }
        int u,v;
        rep0(i,0,M){
            scanf("%d%d",&u,&v);
            e[u].pb(v);e[v].pb(u);
            u = Find(u),v = Find(v);
            if(u != v) f[v] = u;
        }
        bcc_cnt = dfs_clock = top = 0;
        MS0(pre);MS0(bccno);
        rep0(i,0,N)if(pre[i] == 0)
            dfs(i,-1);
        printf("Case %d:\n",kase++);
        rep0(i,0,Q){
            int ret;
            scanf("%d%d",&u,&v);
            if(Find(u) != Find(v)) ret = 0;
            else{
                ret = 1;
                rep1(j,1,bcc_cnt){
                    if(bcc[j].find(u) != bcc[j].end() && bcc[j].find(v) != bcc[j].end()&&bcc[j].size() > 2)
                        ret = 2;
                }
            }
            printf("%s\n",ans[ret]);
        }
    }
    return 0;
}
View Code

 

posted @ 2016-02-07 10:56  hxer  阅读(211)  评论(0编辑  收藏  举报