1. 程式人生 > >Tarjan縮點模板 (洛谷P3387)

Tarjan縮點模板 (洛谷P3387)

struct color hide 計算 min -m etc getch 有向圖

題目背景

縮點+DP

題目描述

給定一個n個點m條邊有向圖,每個點有一個權值,求一條路徑,使路徑經過的點權值之和最大。你只需要求出這個權值和。

允許多次經過一條邊或者一個點,但是,重復經過的點,權值只計算一次。

輸入輸出格式

輸入格式:

第一行,n,m

第二行,n個整數,依次代表點權

第三至m+2行,每行兩個整數u,v,表示u->v有一條有向邊

輸出格式:

共一行,最大的點權之和。

輸入輸出樣例

輸入樣例#1: 復制
2 2
1 1
1 2
2 1
輸出樣例#1: 復制
2

說明

n<=10^4,m<=10^5,|點權|<=1000 算法:Tarjan縮點+DAGdp

技術分享圖片
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<queue>
  5 #define maxn 100010
  6 using namespace std;
  7 inline int read()
  8 {
  9     int x=0,f=1;
 10     char ch=getchar();
 11     while(ch<0||ch>9)
 12     {
 13         if(ch==-
) f=-1; 14 ch=getchar(); 15 } 16 while(ch>=0&&ch<=9) 17 { 18 x=x*10+ch-0; 19 ch=getchar(); 20 } 21 return x*f; 22 } 23 int head[maxn],ecnt,vis[maxn],dis[maxn],low[maxn],dfn[maxn],stk[maxn],tot,colortm,color[maxn],top,f[maxn],ans,w[maxn],x[maxn],y[maxn],n,m;
24 struct edge 25 { 26 int u,v,next; 27 }E[maxn]; 28 void add(int u,int v) 29 { 30 E[++ecnt].u=u; 31 E[ecnt].v=v; 32 E[ecnt].next=head[u]; 33 head[u]=ecnt; 34 } 35 void tarjan(int u) 36 { 37 vis[u]=1; 38 stk[++top]=u; 39 low[u]=dfn[u]=++tot; 40 for(int i=head[u];i;i=E[i].next) 41 { 42 int v=E[i].v; 43 if(!dfn[v]) 44 { 45 tarjan(v); 46 low[u]=min(low[u],low[v]); 47 } 48 else if(vis[v]) low[u]=min(low[u],dfn[v]); 49 } 50 if(dfn[u]==low[u]) 51 { 52 ++colortm; 53 vis[u]=0; 54 while(stk[top+1]!=u) 55 { 56 vis[stk[top]]=0; 57 color[stk[top]]=colortm; 58 f[colortm]+=w[stk[top]]; 59 ans=max(ans,f[colortm]); 60 top--; 61 } 62 } 63 } 64 void bfs(int x) 65 { 66 memset(vis,0,sizeof(vis)); 67 memset(dis,0,sizeof(dis)); 68 queue<int>q; 69 q.push(x); 70 vis[x]=1; 71 dis[x]=f[x]; 72 while(!q.empty()) 73 { 74 int u=q.front(); 75 for(int i=head[u];i;i=E[i].next) 76 { 77 int v=E[i].v; 78 if(dis[v]<dis[u]+f[v]) 79 { 80 dis[v]=dis[u]+f[v]; 81 if(!vis[v]) 82 { 83 q.push(v); 84 vis[v]=1; 85 } 86 } 87 } 88 q.pop(); 89 vis[u]=0; 90 } 91 for(int i=1;i<=colortm;++i) ans=max(ans,dis[i]); 92 } 93 int main() 94 { 95 n=read();m=read(); 96 for(int i=1;i<=n;++i) w[i]=read(); 97 for(int i=1;i<=m;++i) 98 { 99 int a=read(),b=read(); 100 add(a,b); 101 x[i]=a; 102 y[i]=b; 103 } 104 for(int i=1;i<=n;++i) 105 { 106 if(!dfn[i]) tarjan(i); 107 } 108 memset(head,0,sizeof(head)); 109 memset(E,0,sizeof(E)); 110 ecnt=0; 111 for(int i=1;i<=m;++i) 112 { 113 if(color[x[i]]!=color[y[i]]) 114 { 115 add(color[x[i]],color[y[i]]); 116 } 117 } 118 119 for(int i=1;i<=colortm;++i) 120 bfs(i); 121 printf("%d\n",ans); 122 return 0; 123 }
View Code

Tarjan縮點模板 (洛谷P3387)