ATM(BZOJ 1179)
题意:
给你一个有向无环图,每个点有一个权值,给定起点,和多个终点。
求到达终点的最大权值。
输入
6 7
1 2
2 3
3 5
2 4
4 1
2 6
6 5
10 12 8 16 1 5
1 4
4 3 5 6
输出
47
思路:
Tarjan 缩点,点权转边权,跑SPFA
感谢nan葛格的博客讲解
code
#include<stdio.h> #include<stack> #include<queue> #include<algorithm> using namespace std; const int mxn=510000; struct Edge { int to,next; }e[mxn<<1],E[mxn<<1]; int n,m,cnt,idx,tot,st,k,ans; int first[mxn<<1],dfn[mxn],low[mxn],w[mxn],W[mxn],bel[mxn],dis[mxn],head[mxn<<1]; bool ins[mxn],vis[mxn]; stack<int> stk; queue<int> q; void add(int from,int to) { e[++cnt].to=to; e[cnt].next=first[from]; first[from]=cnt; } void Tarjan(int x) { dfn[x]=low[x]=++idx; ins[x]=1;stk.push(x); for(int i=first[x];i;i=e[i].next) { int to=e[i].to; if(!dfn[to]) { Tarjan(to); low[x]=min(low[x],low[to]); } else if(ins[to]) low[x]=min(low[x],dfn[to]); } if(low[x]==dfn[x]) { tot++; int top; do { top=stk.top();stk.pop(); ins[top]=0; bel[top]=tot; }while(top!=x); } } void rebuild() { for(int x=1;x<=n;++x) { for(int i=first[x];i;i=e[i].next) { int to=e[i].to; if(bel[x]==bel[to]) continue; E[++cnt].to=bel[to]; E[cnt].next=head[bel[x]]; head[bel[x]]=cnt; } W[bel[x]]+=w[x]; } } void spfa() { dis[bel[st]]=W[bel[st]]; q.push(bel[st]); while(!q.empty()) { int x=q.front();q.pop(); vis[x]=0; for(int i=head[x];i;i=E[i].next) { int to=E[i].to; if(dis[x]+W[to]>dis[to]) { dis[to]=dis[x]+W[to]; if(!vis[to]) { vis[to]=1; q.push(to); } } } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;++i) { int from,to; scanf("%d%d",&from,&to); add(from,to); } for(int i=1;i<=n;++i) { scanf("%d",&w[i]); if(!dfn[i]) Tarjan(i); } cnt=0; rebuild(); scanf("%d%d",&st,&k); spfa(); for(int i=1;i<=k;++i) { int x; scanf("%d",&x); ans=max(ans,dis[bel[x]]); } printf("%d",ans); return 0; } /* 6 7 1 2 2 3 3 5 2 4 4 1 2 6 6 5 10 12 8 16 1 5 1 4 4 3 5 6 */
从0到1很难,但从1到100很容易