传球接力

来源:互联网 发布:mac上的邮箱软件 编辑:程序博客网 时间:2024/04/30 14:05

这里写图片描述
很明显我们需要找出图中的环(肯定有环)
这里写图片描述
如上图,我们找的环为1->4->3->2->1
环的总长度确定了,但是起点并没有确定,我们有两种选择
一个是6->2->1->4->3(总长度16)
另一个为5->4->3->2->1(总长度25)
很明显是第二种长,我们该如何得出答案
令sum为环的长度,但是环的长度中有一条是加入不进去的,那就是起点切入环的点指向这个点的环上边
我们令fi为i的叶子节点的最长的链的长度
我们枚举指向切入点的点,把这边去掉,然后加入f[切入点],即可算出长度,循环环中节点的个数次
取max即可
第一次使用tarjan求环,栈溢出(80)
由于在这道体中每个点只会指向一个点,使用一个for即可找到所有的环
复杂度:O(n)。
注意答案开long long

#include <cstdio>#include <iostream>#include <vector>#include <cstring>using namespace std;const int max1=510000;int r[max1];int a[max1];int max_date[max1];int n,d[max1];int cyclelen;int cycle[max1];int no_r[max1],cnt;bool vis[max1];long long dis_sum=0;long long ans=0;int pre[max1];void js(){    for(int i=1;i<=cyclelen;i++)     ans=max(ans,(long long)dis_sum-d[cycle[i]]+max_date[a[cycle[i]]]);}int main(){    freopen("pass.in","r",stdin);    freopen("pass.out","w",stdout);    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        int x,y;        scanf("%d%d",&x,&y);        a[i]=x;         d[i]=y;        r[x]++;    }    int l=0,rt=0;    for(int i=1;i<=n;i++)     if(r[i]==0) no_r[++rt]=i;    while (l<rt)//求f数组    {        int k=no_r[++l];        if(max_date[k]+d[k]>max_date[a[k]]) max_date[a[k]]=max_date[k]+d[k];        if(--r[a[k]]==0) no_r[++rt]=a[k];    }     for (int i=1; i<=n; ++i)    if (r[i]>0&&!vis[i])    {        int k=i;        cyclelen=0;        dis_sum=0;        do        {            vis[k]=true;            cycle[++cyclelen]=k;            dis_sum+=d[k];            k=a[k];        }while(k!=i);        js();    }    printf("%lld",ans);     return 0;}
原创粉丝点击