【模板】缩点

   Tarjan算法的一个重要应用就是缩点。

放上题目

题目背景

缩点+DP

题目描述

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

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

输入输出格式

输入格式:

第一行,n,m

第二行,n个整数,依次代表点权

第三至m+2行,每行两个整数u,v,表示u->v有一条有向边

 

输出格式:

共一行,最大的点权之和。

  Input

2 2
1 1
1 2
2 1
Output
2

说明

n<=10^4,m<=10^5,点权<=1000

算法:Tarjan缩点+DAGdp


这道题,在我看来,其实与Tarjan并无区别。

  缩点,算法就是名字啊。其意在于将一个环(强连通分量)当做一个点来处理。

  所以我们采用Tarjan求出所有的强连通分量,然后建出DAG(缩点)。

  最后再在建出的新图上面进行DP记搜,找到点权最大的就好了啊。


放上代码。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<queue>
 7 using namespace std;
 8 
 9 const int Ma=1e4+5;
10 int n,m,val[Ma];
11 int head[Ma],ecnt;
12 int dfn[Ma],low[Ma],ti;
13 int sk[Ma],p;
14 bool vis[Ma];
15 int in[Ma],dis[Ma];
16 struct ss{
17     int nxt,to;
18     int self;
19 }d[Ma*10];
20 int fa[Ma];
21 queue<int> q;
22 
23 void add(int a,int b) {
24     d[++ecnt].to=b;
25     d[ecnt].self=a;
26     d[ecnt].nxt=head[a];
27     head[a]=ecnt;
28 }
29 
30 void Tar(int now) {
31     dfn[now]=low[now]=++ti;
32     sk[++p]=now;
33     vis[now]=1;
34     for(int i=head[now];i;i=d[i].nxt) {
35         int nx=d[i].to;
36         if(!dfn[nx]) {
37             Tar(nx);
38             low[now]=min(low[now],low[nx]);
39         }
40         else if(vis[nx]) low[now]=min(low[now],dfn[nx]);
41     }
42     if(low[now]==dfn[now]) {
43         while(sk[p+1]!=now) {
44             val[now]+=val[sk[p]];
45             fa[sk[p]]=now;
46             vis[sk[p]]=0;
47             --p;
48         }
49         val[now]>>=1;
50     }
51 }
52 
53 void po() {
54     for(int i=1;i<=n;i++)
55         if(fa[i]==i) {
56             dis[i]=val[i];
57             if(!in[i]) q.push(i);
58         }
59     while(!q.empty()) {
60         int now=q.front();
61         for (int i=head[now];i;i=d[i].nxt) {
62             int nxt=d[i].to;
63             dis[nxt]=max(dis[nxt],dis[now]+val[nxt]);
64             in[nxt]--;
65             if(!in[nxt]) q.push(nxt);
66         }
67         q.pop();
68     }
69     return;
70 }
71 
72 int main()
73 {
74     scanf("%d%d",&n,&m);
75     for(int i=1;i<=n;i++) scanf("%d",&val[i]);
76     for(int i=1;i<=m;i++) {
77         int a,b;
78         scanf("%d%d",&a,&b);
79         add(a,b);
80     }
81     for(int i=1;i<=n;i++)
82         if(!dfn[i]) Tar(i);
83     ecnt=0;
84     memset(head,0,sizeof head);
85     for(int i=1;i<=m;i++) {
86         int x=fa[d[i].self];
87         int y=fa[d[i].to];
88         if(x!=y) {
89             add(x,y);
90             in[y]++;
91         }
92     }
93     po();
94     int ans=0;
95     for(int i=1;i<=n;i++)
96         if(fa[i]==i) ans=max(ans,dis[i]);
97     cout<<ans<<endl;
98     return 0;
99 }

  完成!可以静候AC了。

    

  你们这题可以用个快读,稍微优化优化,然后就.......

    

祝AC愉快!

 

posted @ 2019-03-08 13:52  鸽子咕  阅读(127)  评论(0编辑  收藏  举报