[模板]tarjan缩点+拓扑排序

题目:给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。

   允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。

题目简述:先tarjan缩点,再从入度为零处进行一次拓扑排序,求最长路即可,话说拓扑排序求最长路真方便。。。

注意: 要明确拓扑的写法,要用栈写最优。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define man 100010
 4 inline int sc()
 5 {    int x=0,f=1;char ch=getchar();
 6     while(!isdigit(ch)){    if(ch==45)f=-1;ch=getchar();}
 7     while(isdigit(ch)) {    x=x*10+ch-48;ch=getchar();}
 8     return x*f;
 9     }
10 /*TEST*/
11 int n,m,c[man],x[man],y[man];
12 /*EDGE*/
13 int head[man<<1],num=0;
14 struct edge
15 {    int next,to,dis;}e[man<<2];
16 inline void add(int from,int to,int dis)
17 {    e[++num].next=head[from];
18     e[num].to=to;
19     e[num].dis=dis;
20     head[from]=num;
21     }
22 /*TARJAN*/
23 int dfn[man],low[man],bel[man],val[man],cnt=0,dep=0;
24 bool vis[man];
25 int sta[man],top=0;
26 void tarjan(int s)
27 {    low[s]=dfn[s]=++dep;vis[s]=1;sta[++top]=s;
28     for(int i=head[s];i;i=e[i].next)
29     {    int to=e[i].to;
30         if(!dfn[to])
31         {    tarjan(to);
32             low[s]=min(low[s],low[to]);
33             }
34         else if(vis[to])
35         {    low[s]=min(low[s],dfn[to]);}
36         }
37     if(low[s]==dfn[s])
38     {    int j;cnt++;
39         do
40         {    j=sta[top--];
41             vis[j]=0;
42             val[cnt]+=c[j];
43             bel[j]=cnt;
44             }while(j!=s);
45         }
46     }
47 /*TOPSORT*/
48 inline void clear()
49 {    memset(e,0,sizeof(e));
50     memset(head,0,sizeof(head));
51     num=0;
52     }
53 int degree[man],dis[man],maxdis=-10;
54 inline void topsort()
55 {    queue<int >q;
56     for(int i=1;i<=cnt;i++)
57         dis[i]=0;
58     for(int i=1;i<=cnt;i++)
59         if(degree[i]==0) q.push(i),dis[i]=val[i];
60     while(q.size()!=0)
61     {    int u=q.front();q.pop();
62         for(int i=head[u];i;i=e[i].next)
63         {    int to=e[i].to;
64             degree[to]--;
65             if(degree[to]==0) q.push(to);
66             dis[to]=max(dis[to],dis[u]+e[i].dis);
67             }
68         }
69     int ans=0;
70     for(int i=1;i<=cnt;i++)
71         ans=max(ans,dis[i]);
72     printf("%d\n",ans);
73     }
74 int main()
75 {    n=sc();m=sc();
76     for(int i=1;i<=n;i++)
77         c[i]=sc();
78     for(int i=1;i<=m;i++)
79     {    x[i]=sc(),y[i]=sc();
80         add(x[i],y[i],0);
81         }
82     for(int i=1;i<=n;i++)
83         if(!dfn[i]) tarjan(i);
84     clear();
85     for(int i=1;i<=m;i++)
86     {    if(bel[ x[i] ]==bel[ y[i] ]) continue;
87         add(bel[x[i]],bel[y[i]],val[bel[y[i]]]);
88         degree[bel[y[i]]]++;
89         }
90     topsort();
91     return 0;
92     } 
时间: 2024-08-08 13:10:14

[模板]tarjan缩点+拓扑排序的相关文章

[ZJOI2007]最大半连通子图 (Tarjan缩点,拓扑排序,DP)

题目链接 Solution 大概是个裸题. 可以考虑到,如果原图是一个有向无环图,那么其最大半联通子图就是最长的一条路. 于是直接 \(Tarjan\) 缩完点之后跑拓扑序 DP就好了. 同时由于是拓扑序DP,要去掉所有的重边. Code #include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=100008; struct sj{int to,next;}a[maxn*10]; ll mo

bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能够引爆的炸弹的显然应该是一个区间里面的,直接对这个区间进行线段树优化建图. 这样可以得到一个带环图,缩点以后这个炸弹能够炸到的炸弹就是从这个点能够走到的点. 但是这个不太好做,不过可以发现最终的炸弹也是一个区间,所以可以通过缩点后的 DAG 来求出左右端点. 时间复杂度 \(O(n\log n)\)

HDU 6165 FFF at Valentine(Tarjan缩点+拓扑排序)

FFF at Valentine Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 575    Accepted Submission(s): 281 Problem Description At Valentine's eve, Shylock and Lucar were enjoying their time as any oth

POJ 3114 - Countries in War(强连通分量+缩点+拓扑排序+DAG最短路)

Countries in War Time Limit:1000MS    Memory Limit:65536KB    64bit IO Format:%I64d & %I64u Appoint description: Description In the year 2050, after different attempts of the UN to maintain peace in the world, the third world war broke out. The impor

UVA 11324.The Largest Clique tarjan缩点+拓扑dp

题目链接:https://vjudge.net/problem/UVA-11324 题意:求一个有向图中结点数最大的结点集,使得该结点集中任意两个结点u和v满足:要目u可以到达v,要么v可以到达u(相互可达也可以). 思路:同一个强联通分量中满足结点集中任意两个结点u和v满足:要目u可以到达v,要么v可以到达u(相互可达也可以).把强联通分量收缩点后得到scc图,让每个scc结点的权值等于他的结点数,则求scc图上权最大的路径.拓扑dp,也可以直接bfs,但是要建立一个新的起点,连接所有入度为0

POJ2762 Going from u to v or from v to u? 强连通分量缩点+拓扑排序

题目链接:https://vjudge.net/contest/295959#problem/I 或者 http://poj.org/problem?id=2762 题意:输入多组样例,输入n个点和m条有向边,问该图中任意两点x, y之间是否满足x可以到y或者y可以到x. 一开始WA的原因是因为没注意到是或者, 如果是并且的话,就是一道简单的强连通分量的题,直接判断整个图是否为一个强连通分量 对于该题, 先用强连通分量进行缩点,简化图.图就变成了DAG,用拓扑排序判断图中点的入度, 图中入度为0

POJ 2762判断单联通(强连通缩点+拓扑排序)

Going from u to v or from v to u? Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 14789   Accepted: 3915 Description In order to make their sons brave, Jiajia and Wind take them to a big cave. The cave has n rooms, and one-way corridors

POJ2762 Going from u to v or from v to u?(强连通缩点+拓扑排序)

Going from u to v or from v to u? Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 15196   Accepted: 4013 Description In order to make their sons brave, Jiajia and Wind take them to a big cave. The cave has n rooms, and one-way corridors

poj 2762 Going from u to v or from v to u?【强连通分量缩点+拓扑排序】

Going from u to v or from v to u? Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 15812   Accepted: 4194 Description In order to make their sons brave, Jiajia and Wind take them to a big cave. The cave has n rooms, and one-way corridors