Codeforces Beta Round #14 (Div. 2) D. Two Paths

来源:互联网 发布:知联会是什么组织 编辑:程序博客网 时间:2024/05/29 20:05

题目链接

题目大意

给定一棵无向树。从中选择两条不相交的路径,使得两条路径的长度乘积最大。
路径不相交定义为两个路径没有公共点。

题解

首先可以想到一个O(n^4)的算法,就是枚举4个点,也就是两条路径,然后判断是否可行。
考虑如何优化,可以先用n^2的复杂度枚举一条路径,然后贪心得去求另一条路径,另一条路径当然越大越好了。
而从树中删掉一条路径,剩下的就是森林了,在每棵树上求一下直径,求出最大值,就可以更新答案了。
这题的数据范围是n<=200,所以O(n^3)足以过掉这道题了。

#include<cstdio>#include<algorithm>using namespace std;const int M=205;struct Edge{    int to,nxt;}edge[M<<1];int T,head[M];void add_edge(int a,int b){    edge[T]=(Edge){b,head[a]};    head[a]=T++;}int fa[M],dep[M];int mx,ID,ans,n;bool mark[M],flag[M];void rec(int x,int f,int d){    if(!dep[x]) fa[x]=f,dep[x]=d;    mark[x]=1;    if(mx<d){        mx=d;        ID=x;    }    for(int i=head[x];~i;i=edge[i].nxt){        if(flag[edge[i].to]||edge[i].to==f) continue;        rec(edge[i].to,x,d+1);    }}int LCA(int a,int b){    if(dep[a]<dep[b]) swap(a,b);    while(dep[a]>dep[b]) flag[a]=1,a=fa[a];    while(a!=b){        flag[a]=1;        flag[b]=1;        a=fa[a],b=fa[b];    }    flag[a]=flag[b]=1;    return a;}void solve(int a,int b){    for(int i=1;i<=n;i++)        flag[i]=mark[i]=0;    int lca=LCA(a,b),l=0;    for(int i=1;i<=n;i++)        if(!mark[i]){            mx=-1;rec(i,0,0);            mx=-1;rec(ID,0,0);            l=max(l,mx);        }    ans=max(ans,l*(dep[a]+dep[b]-dep[lca]*2));}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)        head[i]=-1;    for(int i=1;i<n;i++){        int a,b;        scanf("%d%d",&a,&b);        add_edge(a,b);        add_edge(b,a);    }    rec(1,0,1);    for(int i=1;i<=n;i++)        for(int j=i+1;j<=n;j++)            solve(i,j);    printf("%d\n",ans);    return 0;} 

然而这还不算完,还有O(n^2)的做法。
由于这棵树是联通的,所以选完了两条路径之后肯定存在第三条路径连接着两条路径。
于是枚举一条边,然后树就被分成了两棵树,求出两棵树的直径的最大值,然后就可以更新答案了。

#include<cstdio>#include<algorithm>using namespace std;const int M=205;struct Edge{    int to,nxt;}edge[M<<1];int head[M],T,del,len[2];void add_edge(int a,int b){    edge[T]=(Edge){b,head[a]};    head[a]=T++;}int mx,ID;void rec(int x,int f,int dep){    if(dep>mx){        mx=dep;        ID=x;    }    for(int i=head[x];~i;i=edge[i].nxt){        if(edge[i].to==f||del==(i>>1)) continue;        rec(edge[i].to,x,dep+1);    }}void solve(int x,int f){    mx=-1;    rec(x,0,0);    rec(ID,0,0);    len[f]=mx;}int main(){    int n;    scanf("%d",&n);    for(int i=1;i<=n;i++)        head[i]=-1;    for(int i=1;i<n;i++){        int a,b;        scanf("%d%d",&a,&b);        add_edge(a,b);        add_edge(b,a);    }    int ans=0;    for(int i=0;i<n-1;i++){        del=i;        solve(edge[i<<1].to,0);        solve(edge[i<<1|1].to,1);        ans=max(ans,len[0]*len[1]);    }    printf("%d\n",ans);    return 0;}

思考

如果可以选择k条路径,那可以怎么写呢?

1 0
原创粉丝点击