P3387 【模板】缩点 tarjan
虽说是模板题,但是竟然中间有dp的部分...先tarjan缩点,重新建图.然后记忆化搜索,搜索dag中的最小环.
题干:
题目背景 缩点+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<cstdio> #include<cmath> #include<ctime> #include<queue> #include<algorithm> #include<cstring> using namespace std; #define duke(i,a,n) for(int i = a;i <= n;i++) #define lv(i,a,n) for(int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } int lst[100010],dfn[100010],low[100010],n,m,tot = 0,str[100010],top = 0,vis[100010]; int num[100010],chu[100010],col[100010],len = 0,ans = 0,ru[100001]; int hr[100010],kk[100010],f[100010]; struct node { int l,r,nxt; }a[100010]; void add(int x,int y) { a[++len].l = x; a[len].r = y; a[len].nxt = lst[x]; lst[x] = len; } void tarjan(int x) { dfn[x] = low[x] = ++tot; str[++top] = x; vis[x] = 1; for(int k = lst[x];k;k = a[k].nxt) { int y = a[k].r; if(!dfn[y]) { tarjan(y); low[x] = min(low[x],low[y]); } else if(vis[y]) { low[x] = min(low[x],dfn[y]); } } if(low[x] == dfn[x]) { ans++; int v; do { num[ans]++; vis[str[top]] = 0; v = str[top--]; col[v] = ans; kk[ans] += hr[v]; } while(x != v); } } void search(int x) { if(f[x]) return; int maxnum = 0; f[x] = kk[x]; for(int k = lst[x];k;k = a[k].nxt) { int y = a[k].r; if(!f[y]) search(y); maxnum = max(maxnum,f[y]); } f[x] += maxnum; } int main() { read(n);read(m); duke(i,1,n) { read(hr[i]); } duke(i,1,m) { int x,y; read(x);read(y); add(x,y); } duke(i,1,n) { if(!dfn[i]) tarjan(i); } clean(lst); int u = len; len = 0; duke(i,1,u) { if(col[a[i].l] != col[a[i].r]) { add(col[a[i].l],col[a[i].r]); } } int maxn = 0; duke(i,1,ans) { if(f[i] == 0) { search(i); maxn = max(maxn,f[i]); } } printf("%d\n",maxn); return 0; } /* 2 2 1 1 1 2 2 1 */
只想找一个不会伤害我的人