UESTC 901 方老师抢银行 --Tarjan求强连通分量

思路:如果出现了一个强连通分量,那么走到这个点时一定会在强连通分量里的点全部走一遍,这样才能更大。所以我们首先用Tarjan跑一遍求出所有强连通分量,然后将强连通分量缩成点(用到栈)然后就变成了一个DAG(有向无环图),然后跑一遍DFS,不断加上遍历点的权值,如果到了网吧,则更新一遍答案,因为可以出去了。

求强连通分量时,如果low[u] == dfn[u],说明形成了一个新的强连通分量,且根为u。具体求强连通分量见:http://www.cnblogs.com/whatbeg/p/3776422.html

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <stack>
using namespace std;
#define N 100007

struct Edge
{
    int v,next;
}G[3*N],G2[3*N];

int first[3*N],first2[3*N],low[N],dfn[N];
int instk[N],bel[N],coin[N],iswb[N],wb[N],coin2[N];
int tot,tot2,n,m,Time,cnt,P,K,res;
stack<int> stk;

void addedge(Edge *G,int& tot,int *first,int u,int v)
{
    G[tot].v = v;
    G[tot].next = first[u];
    first[u] = tot++;
}

void Tarjan(int u)
{
    low[u] = dfn[u] = ++Time;
    stk.push(u);
    instk[u] = 1;
    for(int i=first[u];i!=-1;i=G[i].next)
    {
        int v = G[i].v;
        if(!dfn[v])   //树边
        {
            Tarjan(v);
            low[u] = min(low[u],low[v]);
        }
        else if(instk[v])  //回边
            low[u] = min(low[u],dfn[v]);
    }
    if(low[u] == dfn[u])
    {
        cnt++;
        int v;
        do
        {
            v = stk.top();
            stk.pop();
            if(iswb[v])
                wb[cnt] = 1;
            instk[v] = 0;
            coin2[cnt] += coin[v];
            bel[v] = cnt;
            if(v == P)
                P = cnt;
        }while(u != v);
    }
}

void dfs(int u,int sum)
{
    sum += coin2[u];
    if(wb[u])
        res = max(res,sum);
    for(int i=first2[u];i!=-1;i=G2[i].next)
    {
        int v = G2[i].v;
        dfs(v,sum);
    }
}

int main()
{
    int i,j,u,v;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(first,-1,sizeof(first));
        memset(first2,-1,sizeof(first2));
        memset(G,0,sizeof(G));
        memset(G2,0,sizeof(G2));
        memset(iswb,0,sizeof(iswb));
        memset(wb,0,sizeof(wb));
        memset(instk,0,sizeof(instk));
        memset(bel,-1,sizeof(bel));
        memset(coin2,0,sizeof(coin2));
        memset(low,0,sizeof(low));
        memset(dfn,0,sizeof(dfn));
        tot = tot2 = 0;
        Time = cnt = 0;
        while(!stk.empty())
            stk.pop();
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&u,&v);
            addedge(G,tot,first,u,v);
        }
        for(i=1;i<=n;i++)
            scanf("%d",&coin[i]);
        scanf("%d",&P);
        scanf("%d",&K);
        for(i=0;i<K;i++)
        {
            scanf("%d",&v);
            iswb[v] = 1;
        }
        for(v=1;v<=n;v++)  //Tarjan求强连通分量
        {
            if(!dfn[v])
                Tarjan(v);
        }
        for(i=1;i<=n;i++)   //重建为一个DAG
        {
            for(j=first[i];j!=-1;j=G[j].next)
            {
                v = bel[G[j].v];
                u = bel[i];
                if(u != v)  //如果相连点不是一个连通分量
                    addedge(G2,tot2,first2,u,v);  //建桥
            }
        }
        res = -1;
        dfs(P,0);
        printf("%d\n",res);
    }
    return 0;
}

UESTC 901 方老师抢银行 --Tarjan求强连通分量,布布扣,bubuko.com

时间: 2024-10-13 23:30:39

UESTC 901 方老师抢银行 --Tarjan求强连通分量的相关文章

UESTC 898 方老师和缘分 --二分图匹配+强连通分量

这题原来以为是某种匹配问题,后来好像说是强连通的问题. 做法:建图,每个方老师和它想要的缘分之间连一条有向边,然后,在给出的初始匹配中反向建边,即如果第i个方老师现在找到的是缘分u,则建边u->i.这样求出所有的强连通分量,每个强连通分量中方老师和缘分的数目一定是相等的,所以每个方老师一定可以找到与他在同一个强连通分量里的缘分,因为强连通分量中每个点都是可达的,某个方老师找到了其强连通分量中的非原配点,则该原配缘分一定可以在强连通分量中找到"新欢".可以画个图看看. 由于要构造非

UESTC 917 方老师的分身IV --求欧拉路径

判断欧拉路径是否存在及求出字典序最小的欧拉路径问题(如果存在). 将字符串的第一个字母和最后一个字母间连边,将字母看成点,最多可能有26个点(a-z),如果有欧拉路径,还要判断是否有欧拉回路,如果有,则需要找一个字典序最小的点开始生成这条链,否则以起点开始生成链,起点即为出度比入度大1的点. 欧拉路径是否存在的判定: 1.全部点在一个联通块                               ----用并查集判联通块的数量2.所有点出度入度相等                      

CCF 高速公路 tarjan求强连通分量

问题描述 某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路. 现在,大臣们帮国王拟了一个修高速公路的计划.看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能.如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对. 国王想知道,在大臣们给他的计划中,有多少个便利城市对. 输入

UVALive 4262——Trip Planning——————【Tarjan 求强连通分量个数】

Road Networks Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVALive 4262 Description There is a road network comprised by M<tex2html_verbatim_mark> roads and N<tex2html_verbatim_mark> cities.

hdu 1269 tarjan求强连通分量

tarjan求强连通分量的裸题复习,直接上代码: 1 #include <stack> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 const int N = 10001; 7 const int M = 100000; 8 int dfn[N], low[N], head[N]; 9 bool inStack[N]; 10 int n, m, e, cnt, dfs_clock

Tarjan求强连通分量、求桥和割点模板

Tarjan 求强连通分量模板.参考博客 #include<stdio.h> #include<stack> #include<algorithm> using namespace std; const int maxn = 1e3 + 10; const int maxm = 330000 + 10; struct EDGE{ int v, nxt; }Edge[maxm]; int Head[maxn], cnt; int DFN[maxn], LOW[maxn],

tarjan求强连通分量(模板)

https://www.luogu.org/problem/P2341 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=50010; int pre[maxn],other[maxn],last[maxn],l; int n,m; int dfn[maxn],low[maxn],ans[maxn],st[maxn],belong[maxn

POJ-3180 The Cow Prom(tarjan求强连通分量)

题目链接:http://poj.org/problem?id=3180 题目大意:求一个有向图的强连通分量 算法:求强连通分量首选tarjan算法 这里简单说一下tarjan的思路 时间戳是什么:在搜索时访问的最早时间 维护dfn[u]表示u的时间戳 low[u]表示u点所能回到的最早的祖先的时间戳 开一个栈,把搜索的点入栈.搜索时遇到已经搜过的点,取low[u]和dfn[v]的最小值,回溯时取low[u]和low[v]的最小值(标记上传)传到dfn[u]<=low[u]时表示已经回溯到最上面的

poj 2186 tarjan求强连通分量

蕾姐讲过的例题..玩了两天后才想起来做 貌似省赛之后确实变得好懒了...再努力两天就可以去北京玩了! 顺便借这个题记录一下求强连通分量的算法 1 只需要一次dfs 依靠stack来实现的tarjan算法 每次走到一个点 马上把它压入栈中 每次对与这个点相连的点处理完毕 判断是否low[u]==dfn[u] 若是 开始退栈 直到栈顶元素等于u才退出(当栈顶元素等于u也需要pop) 每次一起退栈的点属于同一个强连通分量 储存图可以用链式前向星也可以用邻接矩阵更可以用vector 蕾姐说不会超时 我信