洛谷P3387 【模板】缩点
题目背景
缩点+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 <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <stack>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
int last[100100],len=0,sccno[10010]={0},scc=0,n,m,u,v,w[10010]={0};
int dfn[10010]={0},low[10010]={0},dfscnt=0,wscc[10010]={0};
int f[100010]={0},t[100010]={0},ans=-2147483648,dis[10010]={0};
bool vis[10010];
stack <int> s;
struct edge {
int next,to;
}e[100100];
int gi() {
char c=getchar();bool f=0;int a=0;
while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=1;c=getchar();}
while (c>=‘0‘&&c<=‘9‘) {a=a*10+c-‘0‘;c=getchar();}
return f?-a:a;
}
void add(int x,int y) {
e[++len].to=y;
e[len].next=last[x];
last[x]=len;
}
void init() {
memset(last,-1,sizeof(last));
n=gi();m=gi();
for (int i=1;i<=n;i++) w[i]=gi();
for (int i=1;i<=m;i++) {
u=gi();v=gi();add(u,v);f[i]=u;t[i]=v;
}
}
int tarjan(int r) {
s.push(r);
dfn[r]=low[r]=++dfscnt;
for (int i=last[r];i!=-1;i=e[i].next) {
int y=e[i].to;
if (!dfn[y]) {tarjan(y);low[r]=min(low[r],low[y]);}
else if (!sccno[y]) low[r]=min(low[r],dfn[y]);
}
if (dfn[r]==low[r]) {
scc++;
while (1) {
int x=s.top();sccno[x]=scc;wscc[scc]+=w[x];
s.pop();if (x==r) break;
}
}
}
void build() {
len=0;
memset(last,-1,sizeof(last));
for (int i=1;i<=m;i++) {
if (sccno[f[i]]!=sccno[t[i]]) add(sccno[f[i]],sccno[t[i]]);
}
}
int bfs(int x) {
memset(dis,-1,sizeof(dis));
memset(vis,false,sizeof(vis));
dis[x]=wscc[x];
queue <int> q;
vis[x]=true;q.push(x);
while (!q.empty()) {
int u=q.front();q.pop();vis[u]=false;
for (int i=last[u];i!=-1;i=e[i].next) {
int v=e[i].to;
if (dis[v]<dis[u]+wscc[v]) {
dis[v]=dis[u]+wscc[v];
if (!vis[v]) {vis[v]=true;q.push(v);}
}
}
}
for (int i=1;i<=scc;i++) ans=max(dis[i],ans);
}
int main() {
init();
for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
build();
for (int i=1;i<=scc;i++) bfs(i);
printf("%d\n",ans);
return 0;
}
飞一样的感觉,这一题我是一遍过的!