您的位置:首页 > 其它

Tarjan缩点模板

2017-08-24 16:00 399 查看

题目背景

缩点+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

代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define For(i,a,b) for(register int i=a;i<=b;++i)
using namespace std;
const int maxx=100010;
int dfn[maxx],low[maxx],st[maxx],in[maxx],c[maxx],cnt=0,c_cnt=0,top=0;
int a[maxx/10],d[maxx/10],f[maxx/10],ans=0,dp[maxx];
bool vis[maxx/10];
struct naonuo2B{
int be[maxx/10],ne[maxx],to[maxx],e;
void add(int x,int y){
to[++e]=y; ne[e]=be[x]; be[x]=e;
}
}Old,New;

int read(){
char x;
while((x=getchar())<'0' || x>'9');
int u=x-'0';
while((x=getchar())>='0' && x<='9') u=u*10+x-'0';
return u;
}
void tarjan(int id){
st[++top]=id;
dfn[id]=low[id]=++cnt;
in[id]=1;
for(int i=Old.be[id];i;i=Old.ne[i]){
int go=Old.to[i];
if(!dfn[go]){
tarjan(go);
low[id]=min(low[go],low[id]);
}
else if(in[go])
low[id]=min(low[id],dfn[go]);
}
if(dfn[id]==low[id]){
in[id]=0;
c[id]=++c_cnt;
f[c_cnt]=a[id];
while(id!=st[top]){
//            printf("%d ",st[top]);
c[st[top]]=c_cnt;
f[c_cnt]+=a[st[top]];
in[st[top]]=0;
top--;
}
top--;
//        printf("%d %d\n",c_cnt,f[c_cnt]);
}
}
void naohengkaihaochou(int x){
For(i,1,x){
for(int j=Old.be[i];j;j=Old.ne[j]){
int go=Old.to[j];
if(c[go]!=c[i] && !vis[c[go]]){
vis[c[go]]=1;
d[c[go]]++;
New.add(c[i],c[go]);
//                printf("%d~%d\n",c[i],c[go]);
}
}
for(int j=Old.be[i];j;j=Old.ne[j]){
int go=Old.to[j];
if(c[go]!=c[i])
vis[c[go]]=0;
}
}
}
int dfs(int id){
dp[id]=max(dp[id],f[id]);
ans=max(dp[id],ans);
for(int i=New.be[id];i;i=New.ne[i]){
int go=New.to[i];
if(dp[go]>=dp[id]+f[go]) continue;
dp[go]=dp[id]+f[go];
dfs(go);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
freopen("output.out","w",stdout);
#endif
int i,j,k,m,n;
n=read(); m=read();
For(i,1,n) a[i]=read();

For(i,1,m){
j=read(); k=read();
Old.add(j,k);
}
For(i,1,n) if(!dfn[i]) tarjan(i);
naohengkaihaochou(n);
For(i,1,c_cnt)
if(!d[i]){
dfs(i);
}
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  模板