E.The Fastest runner ms.zhang

给一个图,n点n边,问走过所有点的最优方案(总路程最小;其次,起点的序号最小;再次,终点的序号最小)

网上有代码的其实。。。只是看不惯那冗长的代码和较慢的运行速度,就决定自己写一个

整棵树只有n-1边,这种图的话就是一个环连着几棵子树

s和t之间肯定有1条路只走1次,其他路走2次

最短路程有2种情况:

s和t最短路不过环,则st最短路全程在树上,环只走1次,设dis(s,t)是s和t间最短路,looplength是环长度,则答案是2*n-looplength-dis(s,t)

这部分树dp就能解决,不过要注意最大次大值的取值问题(最后的WA就是因为这个)和序号的最小化

s和t最短路过环,则st通路有环部分,由于这种情况环部分的路径不可能覆盖全环,没有被通路覆盖的部分路必须走2次

由于只要覆盖全点,走2次那部分有1条边不用走,少走2次

通路可以选择上面或下面,这样就要选择最长覆盖以减少走2次的路

求这个要用扫描线o(n)的方法防超时

求出区间前缀(不横跨环上0点)和后缀(横跨环上0点)里面元素的最大值与扫描线的距离

距离是dep[i]+i+dep[j]-j,就是说随着扫描线和区间内最大值的变化,要加减的值是按它们序号来的

同样要注意序号最小化

被坑了2天,真不该(坑点:序号最小化)

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<stdlib.h>
#include<cmath>
#include<string>
#include<algorithm>
#include<iostream>
using namespace std;
typedef __int64 ll;
const int N=200025;
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
int cnt;
int head[N],inu[N],circ[N];
int dep[N][2],pto[N][2],cto[N][2];
int que[N],lop[N];
int to[N<<1],nxt[N<<1];
void addedge(int u,int v)
{
    to[cnt]=v;nxt[cnt]=head[u];head[u]=cnt++;
    to[cnt]=u;nxt[cnt]=head[v];head[v]=cnt++;
}
//相同路径数的索引号选择
void isvalid(int& a,int& b,int c,int d)
{
    int cmpr=min(a,b)-min(c,d);
    if(cmpr>0 || (cmpr==0 && max(a,b)>max(c,d)))
        a=c,b=d;
}
void bfs(int n)
{
    memset(dep,0,sizeof(dep));
    memset(circ,0,sizeof(circ));
    int tai=0,hed=0,i,u,v;
    for(i=0;i<n;i++)
    {
        if(inu[i]==1)que[tai++]=i;
        pto[i][0]=pto[i][1]=cto[i][0]=cto[i][1]=i;//深度为0,则端点就是本身
    }
    while(tai!=hed)
    {
        u=que[hed++];inu[u]--;
        if(circ[u]==dep[u][0]+dep[u][1])
        {
            isvalid(cto[u][0],cto[u][1],pto[u][0],pto[u][1]);
        }
        else if(circ[u]<dep[u][0]+dep[u][1])
        {
            circ[u]=dep[u][0]+dep[u][1];
            cto[u][0]=pto[u][0];
            cto[u][1]=pto[u][1];
        }
        for(i=head[u];i!=-1;i=nxt[i])
        {
            v=to[i];
            if(inu[v]<=0)continue;
            if(dep[v][0]<dep[u][0]+1)
            {
                if(dep[v][1]<dep[v][0])
                {
                    dep[v][1]=dep[v][0];
                    pto[v][1]=pto[v][0];
                }
                else if(dep[v][1]==dep[v][0] && pto[v][1]>pto[v][0])
                {
                    pto[v][1]=pto[v][0];
                }
                dep[v][0]=dep[u][0]+1;
                pto[v][0]=pto[u][0];
            }
            else if(dep[v][0]==dep[u][0]+1 && pto[v][0]>pto[u][0])
            {
                pto[v][0]=pto[u][0];
            }
            else if(dep[v][1]<dep[u][0]+1)
            {
                dep[v][1]=dep[u][0]+1;
                pto[v][1]=pto[u][0];
            }
            else if(dep[v][1]==dep[u][0]+1 && pto[v][1]>pto[u][0])
            {
                pto[v][1]=pto[u][0];
            }
            if(circ[v]==circ[u])
            {
                isvalid(cto[v][0],cto[v][1],cto[u][0],cto[u][1]);
            }
            else if(circ[v]<circ[u])
            {
                circ[v]=circ[u];
                cto[v][0]=cto[u][0];
                cto[v][1]=cto[u][1];
            }
            if(--inu[v]==1)
            {
                que[tai++]=v;
            }
        }
    }
}
int main()
{
    int t,n,u,v,ans,bestu,bestt,i;
    scanf("%d",&t);
    for(int h=1;h<=t;h++)
    {
        ans=99999999;bestu=99999999;bestt=99999999;
        memset(head,-1,sizeof(head));cnt=0;
        memset(inu,0,sizeof(inu));
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&u,&v);u--,v--;
            addedge(u,v),inu[u]++,inu[v]++;
        }
        bfs(n);
        int lpl=0,max1=-99999999,pmax1=99999999,max2=-99999999,pmax2=99999999;
        for(i=0;inu[i]==0;i++);
        for(u=i;inu[u]>=2;u=to[v])
        {
            lop[lpl++]=u;
            for(v=head[u];v!=-1 && inu[to[v]]<2;v=nxt[v]);
            if(v==-1)break;
            inu[u]--;
        }
        lop[lpl]=lop[0];
        for(i=0;i<lpl;i++)
        {
            if(circ[lop[i]]==dep[lop[i]][0]+dep[lop[i]][1])
            {
                isvalid(cto[lop[i]][0],cto[lop[i]][1],pto[lop[i]][0],pto[lop[i]][1]);
            }
            else if(circ[lop[i]]<dep[lop[i]][0]+dep[lop[i]][1])
            {
                circ[lop[i]]=dep[lop[i]][0]+dep[lop[i]][1];
                cto[lop[i]][0]=pto[lop[i]][0];
                cto[lop[i]][1]=pto[lop[i]][1];
            }
        }
        for(i=0;i<lpl;i++)
        {
            int tmp=2*n-lpl-circ[lop[i]];//s and t are put in the same trees
            if(ans==tmp)
            {
                isvalid(bestu,bestt,cto[lop[i]][0],cto[lop[i]][1]);
            }
            else if(ans>tmp)
            {
                ans=tmp;
                bestu=cto[lop[i]][0];
                bestt=cto[lop[i]][1];
            }
            //notice:The loop can walk without 1 edge
            if(pmax1!=99999999)
            {
                tmp=2*n-(i+dep[lop[i]][0]+max1)-2;
                if(ans==tmp)
                {
                    isvalid(bestu,bestt,pto[lop[i]][0],pto[lop[pmax1]][0]);
                }
                else if(ans>tmp)
                {
                    ans=tmp;
                    bestu=pto[lop[i]][0];
                    bestt=pto[lop[pmax1]][0];
                }
            }
            if(max1<dep[lop[i]][0]-i)
            {
                max1=dep[lop[i]][0]-i;
                pmax1=i;
            }
            else if(max1==dep[lop[i]][0]-i && pto[lop[pmax1]][0]>pto[lop[i]][0])
            {
                pmax1=i;
            }
            if(pmax2!=99999999)
            {
                tmp=2*n-(lpl-i+dep[lop[lpl-i-1]][0]+max2)-2;
                if(ans==tmp)
                {
                    isvalid(bestu,bestt,pto[lop[lpl-i-1]][0],pto[lop[pmax2]][0]);
                }
                else if(ans>tmp)
                {
                    ans=tmp;
                    bestu=pto[lop[lpl-i-1]][0];
                    bestt=pto[lop[pmax2]][0];
                }
            }
            if(max2<dep[lop[lpl-i-1]][0]+i)
            {
                max2=dep[lop[lpl-i-1]][0]+i;
                pmax2=lpl-i-1;
            }
            else if(max2==dep[lop[lpl-i-1]][0]+i && pto[lop[pmax2]][0]>pto[lop[lpl-i-1]][0])
            {
                pmax2=lpl-i-1;
            }
        }
        printf("Case #%d: %d %d %d\n",h,ans,min(bestu,bestt)+1,max(bestu,bestt)+1);
    }
    return 0;
}
View Code

相关文章: