缩点(模板)P3387

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=10000+15;
 4 int n,m,sum,tim,s;
 5 int p[maxn],head[maxn],sd[maxn],dfn[maxn],low[maxn];//DFN(u)为节点u搜索被搜索到时的次序编号(时间戳),
 6                                                     //Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号
 7 int vis[maxn];//栈只为了表示此时是否有父子关系
 8 int h[maxn],in[maxn],dist[maxn];
 9 struct EDGE{ int to;int next;int from; }edge[maxn*10],ed[maxn*10];
10 void add(int from,int to){
11     edge[++sum].next=head[from];
12     edge[sum].from=from;
13     edge[sum].to=to;
14     head[from]=sum;
15 }
16 stack<int>q;
17 void tarjan(int x)
18 {
19     low[x]=dfn[x]=++tim;
20     q.push(x);vis[x]=1;
21     for (int i=head[x];i;i=edge[i].next)
22     {
23         int v=edge[i].to;
24         if(!dfn[v]){
25             tarjan(v);
26             low[x]=min(low[x],low[v]);
27         }
28         else if(vis[v]){
29             low[x]=min(low[x],low[v]);
30         }
31     }
32     if(dfn[x]==low[x]){
33         int y;
34         while(y=q.top()){
35             q.pop();
36             sd[y]=x;
37             vis[y]=0;
38             if (x==y)
39                 break;
40             p[x]+=p[y];
41         }
42     }
43 }
44 int topo()
45 {
46     queue<int>q;
47     int tot=0;
48     for(int i=1;i<=n;i++)
49         if(sd[i]==i&&!in[i])
50             q.push(i),dist[i]=p[i];
51     while(!q.empty()){
52         int k=q.front();q.pop();
53         for(int i=h[k];i;i=ed[i].next){
54             int v=ed[i].to;
55             dist[v]=max(dist[v],dist[k]+p[v]);
56             if(--in[v]==0)q.push(v);
57         }
58     }
59     int ans=0;
60     for(int i=1;i<=n;i++)
61     ans=max(ans,dist[i]);
62     return ans;
63 }
64 int main()
65 {
66     scanf("%d%d",&n,&m);
67     for(int i=1;i<=n;i++)
68     scanf("%d",&p[i]);
69     for(int i=1,u,v;i<=m;i++){
70         scanf("%d%d",&u,&v);
71         add(u,v);
72     }
73     for(int i=1;i<=n;i++)
74         if(!dfn[i])tarjan(i);
75     for(int i=1;i<=m;i++){
76         int x=sd[edge[i].from],y=sd[edge[i].to];
77         if (x!=y){
78             ed[++s].next=h[x];
79             ed[s].to=y;
80             ed[s].from=x;
81             h[x]=s;
82             in[y]++;
83         }
84     }
85     printf("%d",topo());
86     return 0;
87 }
View Code(1)

 

#include<bits/stdc++.h>
using namespace std;
const int maxn=10000+15;
int n,m,sum,tim,top,s;
int p[maxn],head[maxn],sd[maxn],dfn[maxn],low[maxn];//DFN(u)为节点u搜索被搜索到时的次序编号(时间戳),
                                                    //Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号
int stac[maxn],vis[maxn];//栈只为了表示此时是否有父子关系
int h[maxn],in[maxn],dist[maxn];
struct EDGE{ int to;int next;int from; }edge[maxn*10],ed[maxn*10];
void add(int from,int to){
	edge[++sum].next=head[from];
	edge[sum].from=from;
	edge[sum].to=to;
	head[from]=sum;
}
void tarjan(int x)
{
	low[x]=dfn[x]=++tim;
	stac[++top]=x;vis[x]=1;
	for (int i=head[x];i;i=edge[i].next)
	{
		int v=edge[i].to;
		if(!dfn[v]){
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
	    else if(vis[v]) low[x]=min(low[x],low[v]);
	}
	if(dfn[x]==low[x]){
		int y;
		while(y=stac[top--]){
			sd[y]=x;
			vis[y]=0;
			if (x==y) break;
			p[x]+=p[y];
		}
	}
}
int topo()
{
	queue<int>q;
	int tot=0;
	for(int i=1;i<=n;i++)
        if(sd[i]==i&&!in[i])
            q.push(i),dist[i]=p[i];
	while(!q.empty())
	{
		int k=q.front();q.pop();
		for(int i=h[k];i;i=ed[i].next){
			int v=ed[i].to;
			dist[v]=max(dist[v],dist[k]+p[v]);
			if(--in[v]==0)q.push(v);
		}
	}
    int ans=0;
    for(int i=1;i<=n;i++)
    ans=max(ans,dist[i]);
    return ans;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	scanf("%d",&p[i]);
	for(int i=1;i<=m;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
	}
	for(int i=1;i<=n;i++)
	if(!dfn[i]) tarjan(i);
	for(int i=1;i<=m;i++)
	{
		int x=sd[edge[i].from],y=sd[edge[i].to];
		if (x!=y)
		{
			ed[++s].next=h[x];
			ed[s].to=y;
			ed[s].from=x;
            h[x]=s;
			in[y]++;
		}
	}
	printf("%d",topo());
	return 0;
}

  

posted @ 2021-04-21 10:59  Acception  阅读(33)  评论(0)    收藏  举报