题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1179
一道用 Tarjan 缩点+SPFA 最长路的题(Tarjan 算法:http://www.cnblogs.com/hadilo/p/5889333.html )
我们可以这样考虑,把一个连通块缩成一个点,点权为所有权值和,且只要一个点有酒吧那么该点也就有酒吧
因为当我们进入该连通块任意一个点时,显然把它里面所有的点都抢一遍才使答案最优,而且能回到原进入点,并且只要有一个有酒吧就可以选择在那里庆祝
缩完点后,就可以用 SPFA 求最长路,边权变为点权,因为里面已经没有环了,所以可以用
当然最大路也可以用 Dijkstra 或 DP 等方法做
还有这道题细节很多很多,调了我4个多小时QuQ
1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<queue> 8 #include<stack> 9 #define N 500001 10 using namespace std; 11 12 int t,first[N],next[N],back[N],last[N],v[N],a[N],dfn[N],low[N],ans,d[N]; 13 bool f[N],g[N],b[N]; 14 stack<int> s; 15 queue<int> q; 16 void tarjan(int x) 17 { 18 dfn[x]=low[x]=++t; 19 s.push(x); 20 int i; 21 for (i=first[x];i;i=next[i]) 22 { 23 if (f[v[i]]) continue; 24 if (dfn[v[i]]) low[x]=min(low[x],dfn[v[i]]); 25 else 26 { 27 tarjan(v[i]); 28 low[x]=min(low[x],low[v[i]]); 29 } 30 } 31 if (dfn[x]==low[x]) 32 { 33 int k,c=first[x]; 34 while (s.top()!=x) 35 { 36 i=c; 37 k=s.top(); 38 f[k]=b[k]=1; 39 s.pop(); 40 a[x]+=a[k]; 41 g[x]|=g[k]; 42 while (next[i]) i=next[i]; 43 next[i]=first[k]; 44 c=i; 45 for (i=last[k];i;i=back[i]) v[i]=x; 46 } 47 f[s.top()]=1; 48 s.pop(); 49 } 50 } 51 int main() 52 { 53 int n,m,i,x,k; 54 scanf("%d%d",&n,&m); 55 for (i=1;i<=m;i++) 56 { 57 scanf("%d%d",&x,&v[i]); 58 next[i]=first[x]; 59 first[x]=i; 60 back[i]=last[v[i]]; 61 last[v[i]]=i; 62 } 63 for (i=1;i<=n;i++) 64 { 65 scanf("%d",&a[i]); 66 g[i]=b[i]=f[i]=0; 67 } 68 scanf("%d%d",&k,&m); 69 for (i=1;i<=m;i++) 70 { 71 scanf("%d",&x); 72 g[x]=1; 73 } 74 tarjan(k); 75 for (i=1;i<=n;i++) f[i]=1; 76 d[k]=a[k]; 77 q.push(k); 78 while (!q.empty()) 79 { 80 k=q.front(); 81 q.pop(); 82 if (g[k]) ans=max(ans,d[k]); 83 for (i=first[k];i;i=next[i]) 84 { 85 if (b[v[i]]||v[i]==k) continue; 86 if (d[v[i]]<d[k]+a[v[i]]) 87 { 88 d[v[i]]=d[k]+a[v[i]]; 89 q.push(v[i]); 90 } 91 } 92 } 93 cout<<ans<<endl; 94 return 0; 95 }
这道题需要开无限栈,因为递归的 Tarjan 会爆栈,然而并不会手写栈
BZOJ 上幸好开了无限栈,不然就 RE 了,不过其它的 OJ 好像没有开无限栈,RE 两个点……
只好去网上下了一个代码,在 CodeVS 上交了一发手写栈的 Tarjan,终于A了orz(手写栈的戳这里: http://www.cnblogs.com/hadilo/p/5892791.html )
版权所有,转载请联系作者,违者必究
QQ:740929894
时间: 2024-11-09 05:46:49