Tarjan & LCA 套题题目题解

刷题之前来几套LCA的末班

对于题目

HDU 2586 How far away

2份在线模板第一份倍增,倍增还是比较好理解的

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 40040;
const int MAXM = MAXN * 2;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,w;
    int next;
}edge[MAXM];
int head[MAXN],tot;
int N;

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

int dep[MAXN],fa[MAXN],cost[MAXN];
int sumcost[MAXN][20],anc[MAXN][20];
bool vis[MAXN];

void bfs(int root)
{
    memset(vis,false,sizeof(vis));
    queue<int>q;
    q.push(root);
    vis[root] = true;
    fa[root] = -1;
    dep[root] = 0;
    cost[root] = 0;
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (vis[v]) continue;
            dep[v] = dep[u] + 1;
            cost[v] = edge[i].w;
            fa[v] = u;
            vis[v] = true;
            q.push(v);
        }
    }
}

void preprocess()
{
    memset(sumcost,0,sizeof(sumcost));
    for (int i = 1 ; i <= N ; i++)
    {
        anc[i][0] = fa[i];
        sumcost[i][0] = cost[i];
        for (int j = 1 ; (1 << j) <= N ; j++) anc[i][j] = -1;
    }
    for (int j = 1 ; (1 << j) <= N ; j++)
    {
        for (int i = 1 ; i <= N ; i++)
        {
            if (anc[i][j - 1] != -1)
            {
                int a = anc[i][j - 1];
                anc[i][j] = anc[a][j - 1];
                sumcost[i][j] = sumcost[i][j - 1] + sumcost[a][j - 1];
            }
        }
    }
}


int query(int p,int q)
{
    int tmp,log;
    if (dep[p] < dep[q]) swap(p,q);
    for (log = 1 ; (1 << log) <= dep[p] ; log++); log--;
    int ans = 0;
    for (int i = log ; i >= 0 ; i--)
    {
        if (dep[p] - (1 << i) >= dep[q])
        {
            ans += sumcost[p][i];
            p = anc[p][i];
        }
    }
    if (p == q) return ans;
    for (int i = log ; i >= 0 ; i--)
    {
        if (anc[p][i] != -1 && anc[p][i] != anc[q][i])
        {
            ans += sumcost[p][i]; p = anc[p][i];
            ans += sumcost[q][i]; q = anc[q][i];
        }
    }
    ans += cost[p];
    ans += cost[q];
    return ans;
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        init();
        int Q;
        scanf("%d%d",&N,&Q);
        for (int i = 0 ; i < N - 1 ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w);
            add_edge(v,u,w);
        }
        bfs(1);
        //printf("%d %d %d %d\n",fa[2],fa[3],cost[2],cost[3]);
        preprocess();
        //printf("%d %d %d %d\n",anc[2][0],anc[3][0],sumcost[2][0],sumcost[3][0]);
        while(Q--)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            printf("%d\n",query(u,v));
        }
    }
    return 0;
}
View Code

第二份DFS+ST+rmq。关于这种算法的解释在代码里有个链接

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626 
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 40010;
const int MAXM = MAXN * 2;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,w;
    int next;
}edge[MAXN * 2];
int head[MAXN],tol;

void init()
{
    memset(head,-1,sizeof(head));
    tol = 0;
}

void add_edge(int u,int v,int w)
{
    edge[tol].u = u;
    edge[tol].v = v;
    edge[tol].w = w;
    edge[tol].next = head[u];
    head[u] = tol++;
}

int ver[MAXN * 2],R[MAXN * 2],first[MAXN],dir[MAXN];
bool vis[MAXN];
int fac[30];
int tot;
int dp[MAXN * 2][30];

void dfs(int u ,int dep)
{
    vis[u] = true; ver[++tot] = u; first[u] = tot; R[tot] = dep;
    for(int i = head[u]; i != -1 ; i=edge[i].next)
        if( !vis[edge[i].v] )
        {
            int v = edge[i].v , w = edge[i].w;
            dir[v] = dir[u] + w;
            dfs(v,dep+1);
            ver[++tot] = u; R[tot] = dep;
        }
}

void ST(int len)
{
    int K = (int)(log((double)len) / log(2.0));
    for(int i = 1 ; i <= len ; i++) dp[i][0] = i;
    for(int j = 1 ; j <= K ; j++)
        for(int i = 1 ; i + fac[j] - 1 <= len ; i++)
        {
            int a = dp[i][j - 1] , b = dp[i + fac[j - 1]][j - 1];
            if(R[a] < R[b]) dp[i][j] = a;
            else            dp[i][j] = b;
        }
}

int RMQ(int x ,int y)
{
    int K = (int)(log((double)(y - x + 1)) / log(2.0));
    int a = dp[x][K] , b = dp[y - fac[K] + 1][K];
    if(R[a] < R[b]) return a;
    else            return b;
}

int LCA(int u ,int v)
{
    int x = first[u] , y = first[v];
    if(x > y) swap(x,y);
    int res = RMQ(x,y);
    return ver[res];
}

int main()
{
    for (int i = 0 ; i < 30 ; i++) fac[i] = (1 << i);
    int T;
    scanf("%d",&T);
    while (T--)
    {
        int N,Q;
        init();
        scanf("%d%d",&N,&Q);
        memset(vis,false,sizeof(vis));
        for (int i = 1 ; i < N ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w);
            add_edge(v,u,w);
        }
        tot = 0;
        dir[1] = 0;
        dfs(1,1);
        /*
        printf("节点 "); for(int i=1; i<=2*N-1; i++) printf("%d ",ver[i]); cout << endl;
        printf("深度 "); for(int i=1; i<=2*N-1; i++) printf("%d ",R[i]);   cout << endl;
        printf("首位 "); for(int i=0; i<=N; i++) printf("%d ",first[i]);    cout << endl; 
        printf("距离 "); for(int i=0; i<=N; i++) printf("%d ",dir[i]);      cout << endl;
        */
        //以上四行表示了该模版的全部数组含义详细LCA RMQ在线分析在http://www.cnblogs.com/scau20110726/archive/2013/05/26/3100812.html
        ST(2 * N - 1);
        while (Q--)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            int lca  = LCA(u,v);
        //    printf("%d %d %d %d %d %d\n",u,v,dir[u],dir[v],lca,dir[lca]);
            printf("%d\n",dir[u] + dir[v] - 2 * dir[lca]);
        }
    }
    return 0;
}
View Code

 

HDU 1269 迷宫城堡

裸题+中文题!

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = 10010;
const int MAXM = 300010;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,next;
    int w;
}edge[MAXM];
int N,M;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN];

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void Tarjan(int u)
{
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v;
        if (!DFN[v])
        {
            Tarjan(v);
            if (Low[u] > Low[v]) Low[u] = Low[v];
        }
        else if (Instack[v] && Low[u] > DFN[v])
            Low[u] = DFN[v];
    }
    if (Low[u] == DFN[u])
    {
        scc++;
        do
        {
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = scc;
            num[scc]++;
        }while (v != u);
    }
}

void deal()
{
    memset(DFN,0,sizeof(DFN));
    memset(Instack,false,sizeof(Instack));
    Index = top = 0;
    scc = 0;
    memset(num,0,sizeof(num));
    for (int i = 1 ; i <= N ; i++)
    {
        if (!DFN[i]) Tarjan(i);
    }
}

int main()
{
    while (scanf("%d%d",&N,&M) != EOF)
    {
        if (N == 0 && M == 0) break;
        init();
        for (int i = 0 ; i < M ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v,9797);
        }
        deal();
        printf("%s\n",scc == 1 ? "Yes" : "No");
    }
    return 0;
}
View Code

POJ 2767 Proving Equivalences

强联通推证明题 缩点后统计入度出度为0的点。具体答案是max(cntdegout = 0,cntdegin = 0)。很水直接看代码

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = 200010;
const int MAXM = 500010;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,next;
    int w;
}edge[MAXM];
int N,M;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN];

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void Tarjan(int u)
{
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v;
        if (!DFN[v])
        {
            Tarjan(v);
            if (Low[u] > Low[v]) Low[u] = Low[v];
        }
        else if (Instack[v] && Low[u] > DFN[v])
            Low[u] = DFN[v];
    }
    if (Low[u] == DFN[u])
    {
        scc++;
        do
        {
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = scc;
            num[scc]++;
        }while (v != u);
    }
}

void deal()
{
    memset(DFN,0,sizeof(DFN));
    memset(Instack,false,sizeof(Instack));
    top = Index = scc = 0;
    memset(num,0,sizeof(num));
    memset(degin,0,sizeof(degin));
    memset(degout,0,sizeof(degout));
    for (int i = 1 ; i <= N ; i++)
    {
        if (!DFN[i]) Tarjan(i);
    }
    if (scc == 1)
    {
        puts("0");
        return;
    }
    int ret1 = 0,ret2 = 0;
    for (int i = 0 ; i < tot ; i++)
    {
        int v = Belong[edge[i].v];
        int u = Belong[edge[i].u];
        if (u == v) continue;
        degin[v]++;
        degout[u]++;
    }
    for (int i = 1 ; i <= scc ; i++)
    {
        if (degin[i] == 0) ret1++;
        if (degout[i] == 0) ret2++;
    }
    printf("%d\n",max(ret1,ret2));
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&N,&M);
        init();
        for (int i = 0 ; i < M ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v,9797);
        }
        deal();
    }
    return 0;
}
View Code

HDU 3836 Equivalent Sets

与上题一样

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = 200010;
const int MAXM = 500010;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,next;
    int w;
}edge[MAXM];
int N,M;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN];

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void Tarjan(int u)
{
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v;
        if (!DFN[v])
        {
            Tarjan(v);
            if (Low[u] > Low[v]) Low[u] = Low[v];
        }
        else if (Instack[v] && Low[u] > DFN[v])
            Low[u] = DFN[v];
    }
    if (Low[u] == DFN[u])
    {
        scc++;
        do
        {
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = scc;
            num[scc]++;
        }while (v != u);
    }
}

void deal()
{
    memset(DFN,0,sizeof(DFN));
    memset(Instack,false,sizeof(Instack));
    top = Index = scc = 0;
    memset(num,0,sizeof(num));
    memset(degin,0,sizeof(degin));
    memset(degout,0,sizeof(degout));
    for (int i = 1 ; i <= N ; i++)
    {
        if (!DFN[i]) Tarjan(i);
    }
    if (scc == 1)
    {
        puts("0");
        return;
    }
    int ret1 = 0,ret2 = 0;
    for (int i = 0 ; i < tot ; i++)
    {
        int v = Belong[edge[i].v];
        int u = Belong[edge[i].u];
        if (u == v) continue;
        degin[v]++;
        degout[u]++;
    }
    for (int i = 1 ; i <= scc ; i++)
    {
        if (degin[i] == 0) ret1++;
        if (degout[i] == 0) ret2++;
    }
    printf("%d\n",max(ret1,ret2));
}

int main()
{
    int T;
    while(scanf("%d%d",&N,&M) != EOF)
    {
        init();
        for (int i = 0 ; i < M ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v,9797);
        }
        deal();
    }
    return 0;
}
View Code

HDU 1827 Summer Holiday

强连通缩点,统计入度为0的就是要通知的人,对于每一个强连通分量只需要通知里面代价最小的那个更新答案即可。水题

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = 1010;
const int MAXM = 2010;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,next;
    int w;
}edge[MAXM];
int N,M;
int ret;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN];
bool flag[MAXN];
int val[MAXN];

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void Tarjan(int u)
{
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v;
        if (!DFN[v])
        {
            Tarjan(v);
            if (Low[u] > Low[v]) Low[u] = Low[v];
        }
        else if (Instack[v] && Low[u] > DFN[v])
            Low[u] = DFN[v];
    }
    if (Low[u] == DFN[u])
    {
        scc++;
        do
        {
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = scc;
            num[scc]++;
        }while (v != u);
    }
}


void calcu()
{
    memset(DFN,0,sizeof(DFN));
    memset(Instack,false,sizeof(Instack));
    Index = top = scc = 0;
    int ans = 0,ret = 0;
    memset(flag,false,sizeof(flag));
    memset(degin,0,sizeof(degin));
    memset(degout,0,sizeof(degout));
    for (int i = 1 ; i <= N ; i++)
    {
        if (!DFN[i]) Tarjan(i);
    }
    for (int i = 0 ; i < tot ; i++)
    {
        int u = Belong[edge[i].u];
        int v = Belong[edge[i].v];
        if (u == v) continue;
        degin[v]++;
        degout[u]++;
    }
    for (int i = 1 ; i <= scc ; i++)
    {
        if (degin[i] == 0)
        {
            ans++;
            int tmp = INF;
            for (int j = 1 ; j <= N ; j++)
            {
                if (Belong[j] == i)
                    tmp = min(tmp,val[j]);
            }
            ret += tmp;
        }
    }
    
    printf("%d %d\n",ans,ret);
}

int main()
{
    while (scanf("%d%d",&N,&M) != EOF)
    {
        for (int i = 1 ; i <= N ; i++)scanf("%d",&val[i]);
        init();
        for (int i = 1 ; i <= M ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v,9797);
        }
        calcu();
    }
    return 0;
}
View Code

HDU 3072 Intelligence System

给了一个含有 n(0<n<=50000) 个节点的有向图,图中的两点之间的通信时要付出代价的(经过的边权之和),但是如果这两个点之间相互可达,代价为 0

问,从给定的节点向其他所有的点通信,所花费的最小代价是多少

先对原图缩点,形成一个 DAG,给的那个定点显然是 DAG 中入度为 0 的点,并且入度为 0 的点肯定只有一个(根据题目的意思)

每个顶点(除了那个定点)必定只有一个入点,那么,对于每个顶点,完全可以选择代价最小的那条入点,贪心的找即可

做了好久忘了咋做的了。上面你的题解是复制的。解法是一样的具体看代码。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = 50010;
const int MAXM = 100010;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,next;
    int w;
}edge[MAXM];
int N,M;
int ret;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN];
bool flag[MAXN];
int val[MAXN];

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void Tarjan(int u)
{
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v;
        if (!DFN[v])
        {
            Tarjan(v);
            if (Low[u] > Low[v]) Low[u] = Low[v];
        }
        else if (Instack[v] && Low[u] > DFN[v])
            Low[u] = DFN[v];
    }
    if (Low[u] == DFN[u])
    {
        scc++;
        do
        {
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = scc;
            num[scc]++;
        }while (v != u);
    }
}


void calcu()
{
    memset(DFN,0,sizeof(DFN));
    memset(Instack,false,sizeof(Instack));
    memset(degin,0,sizeof(degin));
    memset(degout,0,sizeof(degout));
    Index = top = scc = 0;
    for (int i = 0 ; i < N ; i++)
    {
        if (!DFN[i]) Tarjan(i);
    }
    memset(val,0x3f,sizeof(val));
    for (int i = 0 ; i < tot ; i++)
    {
        int u = Belong[edge[i].u];
        int v = Belong[edge[i].v];
        if (u == v) continue;
        val[v] = min(val[v] ,edge[i].w);
    //    printf("%d %d %d\n",v,val[v],edge[i].w);
        //printf("%d\n",edge[i].w);
    }
    LL ret = 0;
    for (int i = 1 ; i <= scc ; i++)
        ret += 1LL * val[i];
    printf("%lld\n",ret - INF);
}

int main()
{
    while (scanf("%d%d",&N,&M) != EOF)
    {
        init();
        int u,v,w;
        for (int i = 0 ; i < M ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w);
        }
        calcu();
    }
    return 0;
    
}
View Code

HDU 3639 Hawk-and-Chicken

有 n(2<=n<=5000) 个人,m(0<m<=30000) 个 support 关系(A support B)。问:哪些人得到的 support 最多。

需要注意的是 support 是可以传递的,比如:A support B && B support C,那么,C 得到的 support 是 2

做法:强连通缩点,出度为0的点就是我们要的可能的最大support。为什么代码里是入度,我记得要处理出这个连通分量里的点是什么。而正向处理是比较麻烦的。

所以变成建反图,从入度为0点处理

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = 5010;
const int MAXM = 60010;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,next;
    int w;
}edge[MAXM];
int N,M;
int ret;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN];
bool flag[MAXN];
int val[MAXN];

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void Tarjan(int u)
{
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v;
        if (!DFN[v])
        {
            Tarjan(v);
            if (Low[u] > Low[v]) Low[u] = Low[v];
        }
        else if (Instack[v] && Low[u] > DFN[v])
            Low[u] = DFN[v];
    }
    if (Low[u] == DFN[u])
    {
        scc++;
        do
        {
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = scc;
            num[scc]++;
        }while (v != u);
    }
}

vector<int>G[MAXN];
int sum;
bool vis[MAXN];

void dfs(int u)
{
    vis[u] = true;
    sum += num[u];
    for (int i = 0 ; i < (int)G[u].size() ; i++)
    {
        int v = G[u][i];
        if (vis[v]) continue;
        dfs(v);
    }
}


vector<int>ans;
int res[MAXN];
void calcu(int kase)
{
    memset(DFN,0,sizeof(DFN));
    memset(Instack,false,sizeof(Instack));
    memset(res,-1,sizeof(res));
    memset(num,0,sizeof(num));
    top = Index = scc = 0;
    for (int i = 0 ; i < N ; i++)
    {
        if (!DFN[i]) Tarjan(i);
    }
    memset(degin,0,sizeof(degin));
    memset(degout,0,sizeof(degout));
    for (int i = 0 ; i <= scc ; i++) G[i].clear();
    for (int i = 0 ; i < tot ; i++)
    {
        int u = Belong[edge[i].u];
        int v = Belong[edge[i].v];
        if (u == v) continue;
        G[v].push_back(u);
        degin[u]++;
        degout[v]++;
    //    printf("%d %d\n",v,u);
    }
    int ret = 0;
    for (int i = 1 ; i <= scc ; i++)
    {
        if (degin[i] == 0)
        {
            sum = 0;
            memset(vis,false,sizeof(vis));
            dfs(i);
            res[i] = sum;
            if (sum > ret)
            {
                ret = sum;
            }
        }
    }
    //cout << ret << endl;
    ans.clear();
    for (int i = 0 ; i < N ; i++)
    {
        if (res[Belong[i]] == ret)
        {
            ans.push_back(i);
        }
    }
    printf("Case %d: %d\n",kase++,ret - 1);
    for (int i = 0 ; i < (int)ans.size() ; i++)
    {
        printf("%d%c",ans[i],i == ans.size() - 1 ? '\n' : ' ');
    }
}

int main()
{
    int kase = 1,T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&N,&M);
        init();
        for (int i = 0 ; i < M ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v,9797);
        }
        calcu(kase++);
    }
    return 0;
}
View Code

HDU 3594 Cactus

仙人掌图+tarjan

我看了别人的题解弄的。代码里有解释和别人的题解链接

/*
题目大意:给你一个图,让你判断他是不是仙人掌图。

仙人掌图的条件是:

1、是强连通图。

2、每条边在仙人掌图中只属于一个强连通分量。

仙人掌图介绍   -->  https://files.cnblogs.com/ambition/cactus_solution.pdf

解题思路:

1、首先得先熟练掌握塔尖tarjan算法的应用。

2、必须了解仙人掌图的三个性质:

(1).仙人掌dfs图中不能有横向边,简单的理解为每个点只能出现在一个强联通分量中。

(2).low[v]<dfn[u],其中u为v的父节点

(3).a[u]+b[u]<2 ,  a[u]为u节点的儿子节点中有a[u]个low值小于u的dfn值。b[u]为u的逆向边条数。

三个性质有一个不满足则不是仙人掌图。
*/

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = 20010;
const int MAXM = 60010;
const int INF = 0x3f3f3f3f;
int fa[MAXN];
int Find(int x) {return x == fa[x] ? x : fa[x] = Find(fa[x]);}
struct Edge
{
    int u,v,next;
    int w;
}edge[MAXM];
int N,M;
int ret;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN];

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

bool flag;
void Tarjan(int u)
{
    int v;
    int cnt = 0;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v;
        if (!DFN[v])
        {
            Tarjan(v);
            if (Low[v] > DFN[u]) flag = false;;
            if (Low[v] < DFN[u]) cnt++;
            if (cnt >= 2) flag = false;
            if (Low[u] > Low[v]) Low[u] = Low[v];
        }
        else if (Instack[v])
        {
            Low[u] = min(Low[u],DFN[v]);
            cnt++;
            if (cnt >= 2) flag = false;
        }
    }
    if (Low[u] == DFN[u])
    {
        scc++;
        do
        {
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = scc;
            num[scc]++;
        }while (v != u);
    }
}


bool calcu()
{
    memset(DFN,0,sizeof(DFN));
    memset(Instack,false,sizeof(Instack));
    top = Index = scc = 0;
    flag = true;
    for (int i = 0 ; i < N ; i++)
    {
        if (!DFN[i]) Tarjan(i);
    }
//    for (int i = 0 ; i < N ; i++) printf("%d ",Belong[i]); putchar('\n');
//    printf("%d\n",scc);
    if (scc != 1) return false;
    return flag;
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&N);
        init();
        int u,v;
        while (scanf("%d%d",&u,&v) != EOF)
        {
            if (u == 0 && v == 0) break;
            add_edge(u,v,9797);
        }
        if (calcu()) puts("YES");
        else puts("NO");
    }
    return 0;
}
View Code

HDU 2242 考研路茫茫――空调教室

枚举桥然后处理处每个点孩子的总数直接做就行

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 20010;
const int MAXM = 200010;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,w;
    int next;
    int id;
    bool cut;
};
Edge edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
bool Instack[MAXN];
bool cut[MAXN];
int num[MAXN];
int add_block[MAXN],N,M;
int bridge,block;
int son[MAXN],val[MAXN];
int sum;
vector<int>G[MAXN];
bool vis[MAXN];
int dep[MAXN];
int ret;

void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
}

void add_edge(int u,int v,int id,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].id = id;
    edge[tot].next = head[u];
    edge[tot].cut = false;
    head[u] = tot++;
}

void Tarjan(int u,int pre)
{
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        v = edge[i].v;
        if (!DFN[v])
        {
            Tarjan(v,edge[i].id);
            if (Low[u] > Low[v]) Low[u] = Low[v];
            if (Low[v] > DFN[u])
            {
                bridge++;
                edge[i].cut = true;
                edge[i ^ 1].cut = true;
            }
        }
        else if (DFN[v] < DFN[u] && edge[i].id != pre)
            Low[u] = min(Low[u],DFN[v]);
    }
    if (Low[u] == DFN[u])
    {
        block++;
        do
        {
            v = Stack[--top];
            Instack[v] = true;
            Belong[v] = block;
            son[block] += val[v];
        }while (v != u);
    }
}




void dfs(int u,int fa)
{
    vis[u] = true;
    son[u] = num[u];
    for (int i = 0 ; i < (int)G[u].size() ; i++)
    {
        int v = G[u][i];
        if (v == fa || vis[v]) continue;
        dep[v] = dep[u] + 1;
        dfs(v,u);
        son[u] += son[v];
    }
}

void calcu()
{
    memset(DFN,0,sizeof(DFN));
    memset(Instack,false,sizeof(Instack));
    memset(num,0,sizeof(num));
    Index = top = block = 0;
    for (int i = 0 ; i < N ; i++)
    {
        if (!DFN[i]) Tarjan(i,-1);
    }
//    for (int i = 0 ; i < N ; i++) printf("%d\n",Belong[i]);
    for (int i = 0 ; i < N ; i++) num[Belong[i]] += val[i];
//    for (int i = 1 ; i <= block ; i++) printf("%d ",num[i]); putchar('\n');
    if (block == 1) 
    {
        puts("impossible");
        return;
    }
    for (int i = 0 ; i <= block ; i++) G[i].clear();
    for (int i = 0 ; i < tot ; i++)
    {
        if (edge[i].cut)
        {
            int u = Belong[edge[i].u];
            int v = Belong[edge[i].v];
            G[u].push_back(v);
            G[v].push_back(u);
        }
    }
    dep[1] = 0;
    memset(vis,false,sizeof(vis));
    memset(son,0,sizeof(son));
    dfs(1,-1);
//    for (int i = 1 ; i <= block ; i++) printf("%d ",son[i]); putchar('\n');
    int ret = INF;
    //printf("%d\n",sum);
    for (int i = 0 ; i < tot ; i++)
    {
        if (edge[i].cut)
        {
            int u = Belong[edge[i].u];
            int v = Belong[edge[i].v];
            if (dep[u] < dep[v]) 
            {
                ret = min(ret,abs(sum - 2 * son[v]));
            }
            else
            {
                ret = min(ret,abs(sum - 2 * son[u]));
            }
        }
    }
    printf("%d\n",ret);
}

int main()
{
    while (scanf("%d%d",&N,&M) != EOF)
    {
        sum = 0;
        for (int i = 0 ; i < N ; i++) scanf("%d",&val[i]);
        for (int i = 0 ; i < N ; i++) sum += val[i];
        init();
        for (int i = 0 ; i < M ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v,i + 1,9797);
            add_edge(v,u,i + 1,9797);
        }
        calcu();
    }
    return 0;
}
View Code

HDU 2460 Network

a数组记得是表示以该点为桥边的较深点的桥是否已经被删除过

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 100010;
const int MAXM = 400010;
struct Edge
{
    int u,v,w;
    int next;
    int id;
    bool cut;
}edge[MAXM];
int head[MAXN],tot;
int N,M;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int block;
bool Instack[MAXN];
int bridge;

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w,int id)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].id = id;
    edge[tot].cut = false;
    edge[tot].next = head[u];
    head[u] =tot++;
}

void Tarjan(int u,int pre)
{
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    int son = 0;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        v = edge[i].v;
        if (!DFN[v])
        {
            son++;
            Tarjan(v,edge[i].id);
            if (Low[u] > Low[v]) Low[u] = Low[v];
            if (Low[v] > DFN[u])
            {
                bridge++;
                edge[i].cut = true;
                edge[i ^ 1].cut = true;
            }
        }
        else if (DFN[v] < DFN[u] && edge[i].id != pre)
            Low[u] = min(Low[u],DFN[v]);
    }
    if (Low[u] == DFN[u])
    {
        block++;
        do
        {
            v = Stack[--top];
            Instack[v] = true;
            Belong[v] = block;
        }while (v != u);
    }
}

vector<int>vec[MAXN];
int father[MAXN],dep[MAXN],a[MAXN];
void LCA_bfs(int root)
{
    memset(dep,-1,sizeof(dep));
    dep[root] = 0;
    a[root] = 0;
    father[root] = -1;
    queue<int>q;
    q.push(root);
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        for (int i = 0 ; i < (int)vec[u].size() ; i++)
        {
            int v = vec[u][i];
            if (dep[v] != -1) continue;
            dep[v] = dep[u] + 1;
            a[v] = 1;
            father[v] = u;
            q.push(v);
        }
    }
}

int ret;
void lca(int u,int v)
{
    if (dep[u] > dep[v]) swap(u,v);
    while (dep[u] < dep[v])
    {
        if (a[v])
        {
            ret--;
            a[v] = 0;
        }
        v = father[v];
    }
    while (u != v)
    {
        if (a[u])
        {
            ret--;
            a[u] = 0;
        }
        if (a[v])
        {
            ret--;
            a[v] = 0;
        }
        u = father[u];
        v = father[v];
    }
}

void calcu(int N)
{
    memset(Instack,false,sizeof(Instack));
    memset(DFN,0,sizeof(DFN));
    Index = top = block = 0;
    bridge = 0;
    for (int i = 1 ; i <= N ; i++)
        if (!DFN[i]) Tarjan(i,-1);
    for (int i = 1 ; i <= N ; i++)
        vec[i].clear();
    for (int u = 1 ; u <= N ; u++)
    {
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            if (edge[i].cut == false) continue;
            int v = edge[i].v;
            vec[Belong[u]].push_back(Belong[v]);
            vec[Belong[v]].push_back(Belong[u]);
        }
    }
   // printf("%d\n",bridge);
    LCA_bfs(1);
    ret = block - 1;
    int Q;
    scanf("%d",&Q);
    while (Q--)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        lca(Belong[u],Belong[v]);
        printf("%d\n",ret);
    }
    putchar('\n');
}

int main()
{
   // freopen("sample.txt","r",stdin);
    int kase = 1;
    while (scanf("%d%d",&N,&M) != EOF)
    {
        if (N == 0 && M == 0) break;
        printf("Case %d:\n",kase++);
        init();
        for (int i = 0 ; i < M ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v,9797,i);
            add_edge(v,u,9797,i);
        }
        calcu(N);
    }
    return 0;
}
View Code

HDU 3849 By Recognizing These Guys, We Find Social Networks Useful

读完提就会做。

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
const int MAXN = 10010;
const int MAXM = 200010;
const int INF = 0x3f3f3f3f;
int N,M;
struct Edge
{
    int u,v,w;
    int next;
   // int id;
    bool cut;
}edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int block;
bool Instack[MAXN];
int bridge;

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w,int id = 9797)
{
    edge[tot].u = u;
    edge[tot].v = v;
   // edge[tot].id = id;
    edge[tot].cut = false;
    edge[tot].next = head[u];
    head[u] =tot++;
}

void Tarjan(int u,int pre)
{
    int v;
    Low[u] = DFN[u] = ++Index;
    Instack[u] = true;
    Stack[top++]= u;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v;
        if (v == pre) continue;
        if (!DFN[v])
        {
            Tarjan(v,u);
            if (Low[u] > Low[v]) Low[u] = Low[v];
            if (Low[v] > DFN[u])
            {
                bridge++;
                edge[i].cut = true;
                edge[i ^ 1].cut = true;
            }
        }
        else if (Instack[v] && Low[u] > DFN[v])
            Low[u] = DFN[v];
    }
    if (Low[u] == DFN[u])
    {
        block++;
        do
        {
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = block;
        }while (u != v);
    }
}

map<string,int>mp;
map<int,string>res;

void calcu()
{
    memset(DFN,0,sizeof(DFN));
    memset(Instack,false,sizeof(Instack));
    Index = top = block = 0;
    bridge = 0;
    Tarjan(1,1);
    for (int i = 1 ; i <= N ; i++)
    {
        if (!DFN[i])
        {
            puts("0");
            return;
        }
    }
    printf("%d\n",bridge);
    for (int i = 0 ; i < tot ; i += 2)
    {
        if (edge[i].cut == false) continue;
        //printf("%s %s\n",res[edge[i].u],res[edge[i].v]);
        cout << res[edge[i].u] << " " << res[edge[i].v] << endl;
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&N,&M);
        init();
        mp.clear();
        res.clear();
        int cas = 1;
        for (int i = 1 ; i <= M ; i++)
        {
            int u,v;
            char src[50],tag[50];
            scanf("%s%s",src,tag);
            if (!mp[src]) 
            {
                res[cas] = src;
                mp[src] = cas++;
            }
            if (!mp[tag]) 
            {
                res[cas] = tag;
                mp[tag] = cas++;
            }
            u = mp[src];
            v = mp[tag];
            add_edge(u,v,9797);
            add_edge(v,u,9797);
        }
        calcu();
    }
    return 0;
}
View Code

HDU 3896  Greatest TC

搜了题解做的。代码里有我搜的题解的解析。太弱了orz

/*
给出一个无向图,询问两个点在删去一条边或者一个点以后能否到达。
 
生成一颗dfs树,然后记录dfn[]、low[]、final[]、deep[]。Final表示离开这个节点的时间。
对于边的询问,询问的节点是a,b,设这个边为g1-g2,其中deep[g1]>deep[g2]。
1. a在g1的子树内,b也在g1的子树内,那么a、b可以到达。
2. a不在g1的子树内,b也不在g1的子树内,那么a、b可以到达。
3. 不妨假设a在g1的子树内,b不在g1的子树内,则判断low[g1]是否≤dfn[g2]。如果是的话,那么a、b可以到达。
4. 其他情况下不能到达。
对于点的询问,询问的节点是a,b,设这个点为g1:
1. 如果a,b都不在g1的子树内。则可行
2. 如果a,b有一个在g1的子树内(设为a),求出在a-g1路径上的倒数第二个点k,如果low[k] < dfn[g1]则可行
3. 如果a,b都在g1的子树内。求出在a-g1路径上的倒数第二个点k1,在b-g1路径上的倒数第二个点k2,判断是否两者的low都<dfn[g1]则可行
4. 其他情况下不能到达。
 
如何判断一个点a是否在g的子树内:
 Dfn[a] >= dfn[g] 且 final[a] <= final[g]
开始怎么都a不了。后然问了学长才发现对于点询问如果a,b,都在g1子树中,如果k1=k2那么直接输出yes好了。。wa了N多次。。
*/

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 100010;
const int MAXM = 1000010;
const int INF = 0x3f3f3f3f;
int N,M;
struct Edge
{
    int u,v,w;
    int next;
   // int id;
    bool cut;
}edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int dep[MAXN];
int leave[MAXN];
int fa[MAXN];
int block;
bool vis[MAXM];
bool Instack[MAXN];
int bridge;

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w,int id = 9797)
{
    edge[tot].u = u;
    edge[tot].v = v;
   // edge[tot].id = id;
    edge[tot].cut = false;
    edge[tot].next = head[u];
    head[u] =tot++;
}

void Tarjan(int u,int pre,int depth)
{
    Low[u] = DFN[u] = ++Index;
    dep[u] = depth ;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        if (vis[i]) continue;
        vis[i] = vis[i ^ 1] = true;
        int v = edge[i].v;
        if (!DFN[v])
        {
            Tarjan(v,u,depth + 1);
            fa[v] = u;
            Low[u] = min(Low[u],Low[v]);
        }
        else
            Low[u] = min(Low[u],DFN[v]);
    }
    leave[u] = Index;
}

void calcu()
{
    memset(vis,false,sizeof(vis));
    memset(DFN,0,sizeof(DFN));
    memset(fa,-1,sizeof(fa));
    Index = top = block = 0;
    bridge = 0;
    for (int i = 1 ; i <= N ; i++)
    {
        if (!DFN[i]) Tarjan(i,i,0);
    }
}

int main()
{
    while (scanf("%d%d",&N,&M) != EOF)
    {
    //    printf("N = %d M = %d\n",N,M);
        init();
        for (int i = 0 ; i < M ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v,9797);
            add_edge(v,u,9797);
        }
        calcu();
        int Q;
        scanf("%d",&Q);
    //    printf("Q = %d\n",Q);
        while (Q--)
        {
            int op;
            scanf("%d",&op);
            if (op == 1)
            {
                int u,v,g1,g2;
                scanf("%d%d%d%d",&u,&v,&g1,&g2);
                bool flag1 = false,flag2 = false;
                if (dep[g1] < dep[g2]) swap(g1,g2);
                if (DFN[u] >= DFN[g1] && leave[u] <= leave[g1]) flag1 = true;
                if (DFN[v] >= DFN[g1] && leave[v] <= leave[g1]) flag2 = true;
                if ((flag1 && flag2) || (!flag1 && !flag2))
                {
                    puts("yes");
                }
                else
                {
                    if (Low[g1] <= DFN[g2])
                    {
                        puts("yes");
                    }
                    else
                    {
                        puts("no");
                    }
                }
            }
            else
            {
                int u,v,g1;
                scanf("%d%d%d",&u,&v,&g1);
                if (u == g1 || v == g1)
                {
                    puts("no");
                    continue;
                }
                bool flag1 = false,flag2 = false;
                if (DFN[u] >= DFN[g1] && leave[u] <= leave[g1]) flag1 = true;
                if (DFN[v] >= DFN[g1] && leave[v] <= leave[g1]) flag2 = true;
                if (!flag1 && !flag2)
                {
                    puts("yes");
                    continue;
                }
                if (flag1 && !flag2)
                {
                    int x = u;
                    while (fa[x] != g1)
                        x = fa[x];
                    if (Low[x] < DFN[g1])
                        puts("yes");
                    else puts("no");
                    continue;
                }
                if (flag2 && !flag1)
                {
                    int y = v;
                    while (fa[y] != g1)
                        y = fa[y];
                    if (Low[y] < DFN[g1])
                        puts("yes");
                    else puts("no");
                    continue;
                }
                if (flag1 && flag2)
                {
                    int x = u;
                    while (fa[x] != g1) x = fa[x];
                    int y = v;
                    while (fa[y] != g1) y = fa[y];
                    if (x == y)
                    {
                        puts("yes");
                        continue;
                    }
                    if (Low[x] < DFN[g1] && Low[y] < DFN[g1])
                        puts("yes");
                    else
                         puts("no");
                     continue;
                }
                puts("no");
            }
        }
    }
    return 0;
}
View Code

HDU 4005 The war

比较难的题目。所点后从最小桥边两个点为起点DFS,找到次小值为答案

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 20010;
const int MAXM = MAXN * 10;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,next;
    int w,id;
    bool cut;
    friend bool operator < (const Edge &a,const Edge &b)
    {
        return a.w < b.w;
    }
}edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
bool Instack[MAXN];
bool cut[MAXN];
int add_block[MAXN];
int bridge,block;
int N,M;

void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
}

void add_edge(int u,int v,int w,int id)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].id = id;
    edge[tot].next = head[u];
    edge[tot].cut = false;
    head[u] = tot++;
}

void Tarjan(int u,int pre)
{
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    int son = 0;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        v = edge[i].v;
        if (edge[i].id == pre) continue;
        if (!DFN[v])
        {
            son++;
            Tarjan(v,edge[i].id);
            if (Low[u] > Low[v]) Low[u] = Low[v];
            if (Low[v] > DFN[u])
            {
                bridge++;
                edge[i].cut = true;
                edge[i ^ 1].cut = true;
            }
        }
        else if (DFN[v] < DFN[u] && edge[i].id != pre)
            Low[u] = min(Low[u],DFN[v]);
    }
    if (Low[u] == DFN[u])
    {
        block++;
        do
        {
            v = Stack[--top];
            Instack[v] = true;
            Belong[v] = block;
        }while (v != u);
    }
}

vector<Edge>G[MAXN];
int ret;
int dfs(int u,int fa)
{
    int fir = INF,sec = INF,tmp,val;
    for (int i = 0 ; i < (int)G[u].size() ; i++)
    {
        int v = G[u][i].v;
        if (v == fa) continue;
        val = G[u][i].w;
        sec = min(sec,val);
        tmp = dfs(v,u);
        sec = min(sec,tmp);
        if (fir > sec) swap(fir,sec);
    }
    ret = min(ret,sec);
    return fir;
}

void calcu()
{
    memset(DFN,0,sizeof(DFN));
    memset(Instack,false,sizeof(Instack));
    Index = bridge = block = 0;
    top = 0;
    for (int i = 1 ; i <= N ; i++)
    {
        if (!DFN[i]) Tarjan(i,-1);
    }
  //  printf("%d\n",block);
    if (block == 1)
    {
        puts("-1");
        return;
    }
    for (int i = 0 ; i <= N ; i++) G[i].clear();
    int posu = -1,val = INF,posv = -1;
    for (int i = 0 ; i < tot ; i++)
    {
        if (edge[i].cut)
        {
            int u = Belong[edge[i].u];
            int v = Belong[edge[i].v];
            Edge tmp;
            tmp.u = u;
            tmp.v = v;
            tmp.w = edge[i].w;
            tmp.cut = true;
            G[u].push_back(tmp);
            if (edge[i].w < val)
            {
                posu = u;
                val = edge[i].w;
                posv = v;
            }
        }
    }
    for (int i = 1 ; i <= block ; i++) sort(G[i].begin() ,G[i].end());
    /*for (int i = 1 ; i <= block ; i++)
    {
        printf("%d :\n",i);
        for (int j = 0 ; j <(int)G[i].size() ; j++)
        {
            printf("%d ",G[i][j].v);
        }
        putchar('\n');
    }*/
    //printf("%d %d\n",posu,posv);
    if (posu == -1 || posv == -1)
    {
        puts("-1");
        return;
    }
    ret = INF;
    dfs(posu,posv);
    dfs(posv,posu);
    printf("%d\n",ret >= INF ? -1 : ret);
}

int main()
{
    while (scanf("%d%d",&N,&M) != EOF)
    {
        init();
        for (int i = 0 ; i < M ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w,i + 1);
            add_edge(v,u,w,i + 1);
        }
        calcu();
    }
    return 0;
}
View Code

HDU 3394 Railway

做了这么多题这是第一道点连通分量的题目。可以的。。一直WA以为是边联通就对。。(⊙﹏⊙)b

注意割点可以属于多个双连通分量

//注意这里是点双联通而且又一个重要的。不可以直接TARJAN后处理Belong然后在处理多余边。一定不可以
//一定要在TARJAN处理处一个联通快就直接更新答案、原因就是这里的是点双联通
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626 
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 20010;
const int MAXM = 200010;
const int INF = 0x3f3f3f3f; 
int N,M;
struct Edge
{
    int u,v,w;
    int next;
   // int id;
    bool cut;
}edge[MAXM];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int cnt[MAXN];
int block;
bool Instack[MAXN];
int num[MAXN];
bool vis[MAXN];
vector<int>res;
int bridge,ret;

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

stack<Edge>S;

void add_edge(int u,int v,int w,int id = 9797)
{
    edge[tot].u = u;
    edge[tot].v = v;
   // edge[tot].id = id;
    edge[tot].cut = false;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void update()
{
    memset(vis,false,sizeof(vis));
    int sum = 0;
    for (int i = 0 ; i < (int)res.size() ; i++)
    {
        int u = res[i];
        vis[u] = true;
    }
    for (int i = 0 ; i <(int)res.size() ; i++)
    {
        int u =res[i];
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (vis[v]) sum++;
        }
    }
    sum /= 2;
    if (sum > res.size()) ret += sum;
}

void Tarjan(int u,int fa)
{
    Low[u] = DFN[u] = ++Index;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v;
        if (v == fa) continue;
        Edge tmp;
        tmp.u = u;
        tmp.v = v;
        if (!DFN[v])
        {
            S.push(tmp);
            Tarjan(v,u);
            Low[u] = min(Low[u],Low[v]);
            if(Low[v] >= DFN[u])//u是割点
            {
                if(Low[v] > DFN[u])
                {
                    bridge++;
                    edge[i].cut = true;
                    edge[i ^ 1].cut = true;
                }
                block++;
                res.clear();
                while(true)
                {
                    Edge x = S.top(); S.pop();
                    if(Belong[x.u] != block)
                    {
                           res.push_back(x.u);
                           Belong[x.u] = block;
                    }
                    if(Belong[x.v] != block)
                    {
                        res.push_back(x.v);
                        Belong[x.v] = block;
                    }
                    if(x.u==u && x.v==v) break;
                }
                update();
            }
        }
        else if(DFN[v] < DFN[u] && v != fa) 
        {
            S.push(tmp);
            Low[u] = min(Low[u],DFN[v]);
        }
    }
}

void calcu()
{
    memset(DFN,0,sizeof(DFN));
    memset(Instack,false,sizeof(Instack));
    memset(num,0,sizeof(num));
    memset(Belong,0,sizeof(Belong));
    Index = top = block = bridge = 0;
    ret = 0;
    for (int i = 0 ; i < N ; i++)
    {
        if (!DFN[i]) Tarjan(i,-1);
    }
    printf("%d %d\n",bridge,ret);
}

int main()
{
    while (scanf("%d%d",&N,&M) != EOF)
    {
        if (N == 0 && M == 0) break;
        init();
        for (int i = 0 ; i < M ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v,9797);
            add_edge(v,u,9797);
        }
        calcu();
    }
    return 0;
}
View Code

HDU 2874 Connections between cities

倍增无难度

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626 
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 10010;
const int MAXM = MAXN * 4;
const int INF = 0x3f3f3f3f;
int FA[MAXN];
int Find(int x) {return x == FA[x] ? x : FA[x] = Find(FA[x]);}
struct Edge
{
    int u,v,w;
    int next;
}edge[MAXM];
int head[MAXN],tot;
int N,M;

void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
    for (int i = 0 ; i <= N ; i++) FA[i] = i;
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

int dep[MAXN],fa[MAXN],cost[MAXN];
int sumcost[MAXN][20],anc[MAXN][20];
bool vis[MAXN];

void bfs(int root)
{
    queue<int>q;
    q.push(root);
    vis[root] = true;
    fa[root] = -1;
    dep[root] = 0;
    cost[root] = 0;
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (vis[v]) continue;
            dep[v] = dep[u] + 1;
            cost[v] = edge[i].w;
            fa[v] = u;
            vis[v] = true;
            q.push(v);
        }
    }
}

void preprocess()
{
    memset(sumcost,0,sizeof(sumcost));
    for (int i = 1 ; i <= N ; i++)
    {
        anc[i][0] = fa[i];
        sumcost[i][0] = cost[i];
        for (int j = 1 ; (1 << j) <= N ; j++) anc[i][j] = -1;
    }
    for (int j = 1 ; (1 << j) <= N ; j++)
    {
        for (int i = 1 ; i <= N ; i++)
        {
            if (anc[i][j - 1] != -1)
            {
                int a = anc[i][j - 1];
                anc[i][j] = anc[a][j - 1];
                sumcost[i][j] = sumcost[i][j - 1] + sumcost[a][j - 1];
            }
        }
    }
}


int query(int p,int q)
{
    int tmp,log;
    if (dep[p] < dep[q]) swap(p,q);
    for (log = 1 ; (1 << log) <= dep[p] ; log++); log--;
    int ans = 0;
    for (int i = log ; i >= 0 ; i--)
    {
        if (dep[p] - (1 << i) >= dep[q]) 
        {
            ans += sumcost[p][i];
            p = anc[p][i];
        }
    }
    if (p == q) return ans;
    for (int i = log ; i >= 0 ; i--)
    {
        if (anc[p][i] != -1 && anc[p][i] != anc[q][i])
        {
            ans += sumcost[p][i]; p = anc[p][i];
            ans += sumcost[q][i]; q = anc[q][i];
        }
    }
    ans += cost[p];
    ans += cost[q];
    return ans;
}

int main()
{
    int M,C;
    while (scanf("%d%d%d",&N,&M,&C) != EOF)
    {
        init();
        for (int i = 0 ; i < M ; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w);
            add_edge(v,u,w);
            int fu = Find(u);
            int fv = Find(v);
            if (fu != fv) FA[fu] = fv;
        }
        memset(vis,false,sizeof(vis));
        for (int i = 1 ; i <= N ; i++) if (!vis[i])
            bfs(i);
        preprocess();
        while (C--)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            int fu = Find(u);
            int fv = Find(v);
        //    printf("%d %d %d %d\n",u,v,fu,fv);
            if (fu == fv)
            {
                printf("%d\n",query(u,v));
            }
            else puts("Not connected");
        }
    }
    return 0;
}
View Code

HDU 3078 Network

直接暴力居然不会T。我也不知道为啥。

所以做法就是直接爆。修改就直接该。Nothing more

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626 
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 80010;
const int MAXM = 160010;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,w;
    int next;
}edge[MAXM];
int head[MAXN],tot;
int N,K;

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

int dep[MAXN],fa[MAXN],val[MAXN];
int anc[MAXN][20];
bool vis[MAXN];

int src[MAXN],cnt;
int cmp(const int &a,const int &b)
{
    return a > b;
}

void bfs(int root)
{
    memset(vis,false,sizeof(vis));
    queue<int>q;
    q.push(root);
    vis[root] = true;
    fa[root] = -1;
    dep[root] = 0;
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        for (int i = head[u] ; i != -1 ; i = edge[i].next)
        {
            int v = edge[i].v;
            if (vis[v]) continue;
            dep[v] = dep[u] + 1;
            fa[v] = u;
            vis[v] = true;
            q.push(v);
        }
    }
}

void preprocess()
{
    for (int i = 1 ; i <= N ; i++)
    {
        anc[i][0] = fa[i];
        for (int j = 1 ; (1 << j) <= N ; j++) anc[i][j] = -1;
    }
    for (int j = 1 ; (1 << j) <= N ; j++)
    {
        for (int i = 1 ; i <= N ; i++)
        {
            if (anc[i][j - 1] != -1)
            {
                int a = anc[i][j - 1];
                anc[i][j] = anc[a][j - 1];
            }
        }
    }
}


int query(int p,int q)
{
    int tmp,log;
    if (dep[p] < dep[q]) swap(p,q);
    for (log = 1 ; (1 << log) <= dep[p] ; log++); log--;
    for (int i = log ; i >= 0 ; i--)
    {
        if (dep[p] - (1 << i) >= dep[q]) 
        {
            p = anc[p][i];
        }
    }
    if (p == q) return p;
    for (int i = log ; i >= 0 ; i--)
    {
        if (anc[p][i] != -1 && anc[p][i] != anc[q][i])
        {
            p = anc[p][i];
            q = anc[q][i];
        }
    };
    return fa[p];
}

void update(int u,int ed)
{
    while (u != ed)
    {
        src[++cnt] = val[u];
        u = fa[u];
    }
}

void slove(int u,int v)
{
    int lca = query(u,v);
//    printf("%d %d %d\n",u,v,lca);
    cnt = 0;
    update(u,lca);
    update(v,lca);
    src[++cnt] = val[lca];
    if (cnt < K)
    {
        puts("invalid request!");
        return;
    }
    sort(src + 1,src + 1 + cnt,cmp);
    printf("%d\n",src[K]);
}

int main()
{
    int Q;
    while (scanf("%d%d",&N,&Q) != EOF)
    {
        init();
        for (int i = 1 ; i <= N ; i++) scanf("%d",&val[i]);
        for (int i = 1 ; i < N ; i++)
        {
            int u,v,w;
            scanf("%d%d",&u,&v);
            add_edge(u,v,9797);
            add_edge(v,u,9797);
        }
        bfs(1);
    //    printf("%d %d %d %d %d\n",fa[1],fa[2],fa[3],fa[4],fa[5]);
        preprocess();
        while (Q--)
        {
            int op;
            scanf("%d",&op);
            if (op == 0)
            {
                int u,cost;
                scanf("%d%d",&u,&cost);
                val[u] = cost;
            }
            else
            {
                K = op;
                int u,v;
                scanf("%d%d",&u,&v);
                slove(u,v);
            }
        }
    }
    return 0;
}
View Code

HDU 3830 Checkers

这题真的神。我醉了。完全抄的比人的代码。感觉如果比赛除了这题必然不会。。膜拜一下

题解看这里讲的非常详细

http://www.cnblogs.com/scau20110726/archive/2013/06/14/3135024.html

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
struct state
{
    LL x,y,z;
    LL dep;
}S,T;

inline bool cmp_state(const state &a,const state &b)
{
    if (a.x == b.x && a.y == b.y && a.z == b.z) return true;
    return false;
}

inline void makeorder(state &a)
{
    LL tmp[5];
    tmp[0] = a.x;
    tmp[1] = a.y;
    tmp[2] = a.z;
    sort(tmp,tmp + 3);
    a.x = tmp[0];
    a.y = tmp[1];
    a.z = tmp[2];
}

state Root(state &a)
{
    state tmp = a;
    tmp.dep = 0;
    LL dep = 0;
    while(abs(tmp.x - tmp.y) != abs(tmp.y - tmp.z))
    {
        LL len = abs(tmp.x - tmp.y);
        LL __len = abs(tmp.y- tmp.z);
        if(__len > len)
        {
            LL c = (__len - 1)/ len;
            dep += c;
            tmp.y += c * len;
            tmp.x += c * len;
        }
        else
        {
            LL c = (len - 1) / __len;
            dep += c;
            tmp.y -= c * __len;
            tmp.z -= c * __len;
        }
    }
    a.dep = dep;
    return tmp;
}

void update(state &a ,LL delta)
{
    LL cnt = 0;
    while(cnt < delta)
    {
        LL len = abs(a.x - a.y);
        LL __len = abs(a.y - a.z);
        LL k = abs(cnt - delta); //还差多少步
        if(len < __len)
        {
            LL c = (__len - 1) / len; //将要移动多少步
            LL Min = min(k , c);
            a.x += Min * len;
            a.y += Min * len;
            cnt += Min;
            if(Min == k) break;
        }
        else
        {
            LL c = (len - 1) / __len;
            LL Min = min(k , c);
            a.y -= Min * __len;
            a.z -= Min * __len;
            cnt += Min;
            if(Min == k) break;
        }
    }
    a.dep -= delta;
}

LL calcu()
{
    state tmpS,tmpT;
    LL low = 0,high = S.dep;
    while (low <= high)
    {
        LL mid = (low + high) / 2;
        LL delta = S.dep - mid;
        tmpS = S;
        tmpT = T;
        update(tmpS,delta);
        update(tmpT,delta);
        if (!cmp_state(tmpS,tmpT))  high = mid - 1;
        else low = mid + 1;
    }
    return 2 * (S.dep - high);
}

int main()
{
    while (scanf("%I64d%I64d%I64d",&S.x,&S.y,&S.z) != EOF)
    {
        scanf("%I64d%I64d%I64d",&T.x,&T.y,&T.z);
        S.dep = T.dep = 0;
        makeorder(S);
        makeorder(T);
        state rs = Root(S);
        state rt = Root(T);
        if (!cmp_state(rs,rt))
        {
            puts("NO");
            continue;
        }
        LL tmpr = abs(S.dep - T.dep);
     //   printf("%I64d %I64d %I64d\n",T.x,T.y,T.z);
        if (S.dep > T.dep) update(S,S.dep - T.dep);
        else update(T,T.dep - S.dep);
        LL ret = calcu();
        puts("YES");
        printf("%I64d\n",ret + tmpr);
    }
    return 0;
}
View Code

HDU 4338 Simple Path

很考验玛丽的一道题、具体怎么做的不太好说。看这里吧。他说的比较好。

就是通过割点。点双连通分量建树,然后树上的关系更新出答案,去重。割点要单独为1个点。

如果查询的点就是割点要选择单独割点为新点的那个店作为新图 。其余情况选择点双连通分量的那个店

这个非常详细 http://blog.csdn.net/julyana_lin/article/details/8128352

代码如下。有些中间调试没删掉。感觉此题比较考验玛丽。仔细看一下发现其实还是很容易些的,多一份写法可能更相似更愿意去看。

#pragma comment(linker, "/STACK:102400000,102400000")
#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 100010;
const int MAXM = 400010;
const int INF = 0x3f3f3f3f;
int N,M;
struct Edge
{
    int u,v,w;
    int next;
   // int id;
    bool cut;
}edge[MAXM];
int head[MAXN],tot;

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

int Low[MAXN],DFN[MAXN];
bool cut[MAXN];
int Stack[MAXN];
int deep,top,bnum,root;
int Index,cas;
vector<int>block[MAXN];

void Tarjan(int u,int pre)
{
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    bool flag = false;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v;
        if (v == pre && !flag)
        {
            flag = true;
            continue;
        }
        if (!DFN[v])
        {
            Tarjan(v,u);
            Low[u] = min(Low[u],Low[v]);
            if (Low[v] >= DFN[u])
            {
                if (pre == -1) root++;
                else cut[u] = true;
                int tmp;
                do
                {
                    tmp = Stack[--top];
                    block[bnum].push_back(tmp);
                }while (tmp != v);
                block[bnum].push_back(u);
                bnum++;
            }
        }
        else Low[u] = min(Low[u],DFN[v]);
    }
}

vector<int>G[MAXN];
int lab[MAXN];
int nb[MAXN];

void calcu()
{
    memset(cut,false,sizeof(cut));
    memset(DFN,0,sizeof(DFN));
    for (int i = 0 ; i <= N ; i++) G[i].clear();
    for (int i = 0 ; i <= N ; i++) block[i].clear();
    top = bnum = Index = 0;
    for (int i = 0 ; i < N ; i++)
    {
        if (!DFN[i])
        {
            root = 0;
            Tarjan(i,-1);
            if (root > 1) cut[i] = true;
        }
    }
    /*
    for (int i = 0 ; i < bnum ; i++)
    {
        for (int j = 0 ; j < (int)block[i].size() ; j++)
            printf("%d ",block[i][j]);
        putchar('\n');
    }*/

    memset(lab,-1,sizeof(lab));
    cas = 0;
    for (int i = 0 ; i < N ; i++)
    {
        if (cut[i])
        {
            lab[i] = cas;
            nb[cas] = 1;
            cas++;
        }
    }
    for (int i = 0 ; i < bnum ; i++)
    {
        for (int j = 0 ; j < (int)block[i].size() ; j++)
        {
            int v = block[i][j];
            if (cut[v])
            {
              //  printf("%d is cut\n",v);
                G[lab[v]].push_back(cas);
                G[cas].push_back(lab[v]);
            }
            else
                lab[v] = cas;
        }
        nb[cas] = block[i].size();
        cas++;
    }
   /* putchar('\n');
    for (int i = 0 ; i < N ; i++) printf("%d ",lab[i]);
    putchar('\n');
    for (int i = 0 ; i < cas ; i++)
    {
        for (int j = 0 ; j < (int)G[i].size() ; j++)
            printf("%d ",G[i][j]);
        putchar('\n');
    }
*/
}

int id[MAXN];
int dep[MAXN],fa[MAXN],cost[MAXN];
int anc[MAXN][20];
bool vis[MAXN];

void bfs(int root)
{
    cost[root] = nb[root];
    fa[root] = -1;
    dep[root] = 0;
    vis[root] = true;
    queue<int>q;
    q.push(root);
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        for (int i = 0 ; i < (int)G[u].size() ; i++)
        {
            int v = G[u][i];
            if (vis[v]) continue;
            vis[v] = true;
            dep[v] = dep[u] + 1;
            fa[v] = u;
            cost[v] = cost[u] + nb[v];
            q.push(v);
        }
    }
}

void preprecess()
{
    for (int i = 0 ; i < cas ; i++)
    {
        anc[i][0] = fa[i];
        for (int j = 1 ; (1 << j) < cas ; j++) anc[i][j] = -1;
    }
    for (int j = 1 ; (1 << j) < cas ; j++)
    {
        for (int i = 0 ; i < cas ; i++)
        {
            if (anc[i][j - 1] != -1)
            {
                int a = anc[i][j - 1];
                anc[i][j] = anc[a][j - 1];
            }
        }
    }
}

int query(int p,int q)
{
    int tmp,log;
    if (dep[p] < dep[q]) swap(p,q);
    for (log = 1 ; (1 << log) <= dep[p] ; log++); log--;
    for (int i = log ; i >= 0 ; i--)
    {
        if (dep[p] - (1 << i) >= dep[q])
            p = anc[p][i];
    }
    if (p == q)return p;
    for (int i = log ; i >= 0 ; i--)
    {
        if (anc[p][i] != -1 && anc[p][i] != anc[q][i])
        {
            p = anc[p][i];
            q = anc[q][i];
        }
    }
    return fa[p];
}

void col(int u,int type)
{
    id[u] = type;
    for (int i = 0 ; i < (int)G[u].size() ; i++)
    {
        int v = G[u][i];
        if (id[v] != -1) continue;
        col(v,type);
    }
}


int main()
{
    int kase = 1;
    while (scanf("%d%d",&N,&M) != EOF)
    {
        init();
        for (int i = 0 ; i < M ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v,9797);
            add_edge(v,u,9797);
        }
        calcu();
        memset(dep,0,sizeof(dep));
        memset(vis,false,sizeof(vis));
        memset(cost,0,sizeof(cost));
        for (int i = 0 ; i < cas ; i++)
            if (dep[i] == 0) bfs(i);
       // for (int i = 0 ; i < 4 ; i++)
       //     printf("%d %d %d %d\n",i,fa[i],dep[i],cost[i]);
        preprecess();
        int Q;
        memset(id,-1,sizeof(id));
        int step = 1;
        for (int i = 0 ; i < cas ; i++)
        {
            if (id[i] == -1)
            {
                col(i,step);
                step++;
            }
        }
        printf("Case #%d:\n",kase++);
        scanf("%d",&Q);
        while (Q--)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            if (u == v)
            {
                printf("%d\n",N - 1);
                continue;
            }
            if (lab[u] == -1 || lab[v] == -1)
            {
                printf("%d\n",N);
                continue;
            }
            if (id[lab[u]] != id[lab[v]])
            {
                printf("%d\n",N);
                continue;
            }
            int realu = lab[u];
            int realv = lab[v];
            int lca = query(realu,realv);
          //  printf("%d %d %d %d %d\n",u,v,realu,realv,lca);
            int sum = cost[realu] + cost[realv] - 2 * cost[lca] + nb[lca];
            int len = dep[realu] + dep[realv] - 2 * dep[lca];
            printf("%d\n",N - (sum - len));
        }
        putchar('\n');
    }
    return 0;
}
View Code

FZU 1719 Spy network

在缩点入度为0的点里选择权最小的求和就是答案。比较容易


#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <stack>
#include <queue>
#include <cctype>
#include <cstdio>
#include <string>
#include <vector>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define PI 3.1415926535897932626
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 5010;
const int MAXM = 10010;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int u,v,next;
    int w;
}edge[MAXM];
int N;
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index,top;
int scc;
bool Instack[MAXN];
int degin[MAXN],degout[MAXN];
int num[MAXN];
int val[MAXN],M;
int MIN[MAXN];

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void add_edge(int u,int v,int w)
{
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void Tarjan(int u)
{
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    for (int i = head[u] ; i != -1 ; i = edge[i].next)
    {
        int v = edge[i].v;
        if (!DFN[v])
        {
            Tarjan(v);
            if (Low[u] > Low[v]) Low[u] = Low[v];
        }
        else if (Instack[v] && Low[u] > DFN[v])
            Low[u] = DFN[v];
    }
    if (Low[u] == DFN[u])
    {
        scc++;
        do
        {
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = scc;
            num[scc]++;
        }while (v != u);
    }
}

void calcu()
{
    memset(DFN,0,sizeof(DFN));
    memset(Instack,false,sizeof(Instack));
    top = Index = scc = 0;
    memset(num,0,sizeof(num));
    for (int i = 1 ; i <= N ; i++)
    {
        if (!DFN[i]) Tarjan(i);
    }
    memset(degin,0,sizeof(degin));
    memset(degout,0,sizeof(degout));
    memset(MIN,0x3f,sizeof(MIN));
    for (int i = 1 ; i <= N ; i++)
    {
        MIN[Belong[i]] = min(MIN[Belong[i]],val[i]);
    }
    for (int i = 0 ; i < tot ; i++)
    {
        int u = Belong[edge[i].u];
        int v = Belong[edge[i].v];
        if(u == v) continue;
        degout[u]++;
        degin[v]++;
    }
    bool flag = false;
    for (int i = 1 ; i <= scc ; i++)
    {
        if (degin[i] == 0 && MIN[i] >= INF)
        {
            flag = true;
            break;
        }
    }
    if (flag)
    {
        puts("NO");
        int pos = - 1;
        for (int i = 1 ; i <= N ; i++)
            if (degin[Belong[i]] == 0 && MIN[Belong[i]] >= INF)
        {
            printf("%d\n",i);
            return;
        }
    }
    else
    {
        puts("YES");
        int ret = 0;
        for (int i = 1 ; i <= scc ; i++) if (degin[i] == 0) ret += MIN[i];
        printf("%d\n",ret);
    }
}

int main()
{
    while (scanf("%d",&N) != EOF)
    {
        init();
        int P;
        scanf("%d",&P);
        memset(val,0x3f,sizeof(val));
        for (int i = 1 ; i <= P ; i++)
        {
            int x,value;
            scanf("%d%d",&x,&value);
            val[x] = min(val[x],value);
        }
        int M;
        scanf("%d",&M);
        for (int i = 0 ; i < M ; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v,9797);
        }
        calcu();
    }
    return 0;
}
View Code

 

 
posted @ 2015-10-08 13:11  Commence  阅读(281)  评论(0编辑  收藏  举报