Codeforces 667D World Tour【最短路+思维】好题!

D. World Tour
time limit per test
5 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

A famous sculptor Cicasso goes to a world tour!

Well, it is not actually a world-wide. But not everyone should have the opportunity to see works of sculptor, shouldn't he? Otherwise there will be no any exclusivity. So Cicasso will entirely hold the world tour in his native country — Berland.

Cicasso is very devoted to his work and he wants to be distracted as little as possible. Therefore he will visit only four cities. These cities will be different, so no one could think that he has "favourites". Of course, to save money, he will chose the shortest paths between these cities. But as you have probably guessed, Cicasso is a weird person. Although he doesn't like to organize exhibitions, he likes to travel around the country and enjoy its scenery. So he wants the total distance which he will travel to be as large as possible. However, the sculptor is bad in planning, so he asks you for help.

There are n cities and m one-way roads in Berland. You have to choose four different cities, which Cicasso will visit and also determine the order in which he will visit them. So that the total distance he will travel, if he visits cities in your order, starting from the first city in your list, and ending in the last, choosing each time the shortest route between a pair of cities — will be the largest.

Note that intermediate routes may pass through the cities, which are assigned to the tour, as well as pass twice through the same city. For example, the tour can look like that: . Four cities in the order of visiting marked as overlines: [1, 5, 2, 4].

Note that Berland is a high-tech country. So using nanotechnologies all roads were altered so that they have the same length. For the same reason moving using regular cars is not very popular in the country, and it can happen that there are such pairs of cities, one of which generally can not be reached by car from the other one. However, Cicasso is very conservative and cannot travel without the car. Choose cities so that the sculptor can make the tour using only the automobile. It is guaranteed that it is always possible to do.

Input

In the first line there is a pair of integers n and m (4 ≤ n ≤ 3000, 3 ≤ m ≤ 5000) — a number of cities and one-way roads in Berland.

Each of the next m lines contains a pair of integers ui, vi (1 ≤ ui, vi ≤ n) — a one-way road from the city ui to the city vi. Note that ui and vi are not required to be distinct. Moreover, it can be several one-way roads between the same pair of cities.

Output

Print four integers — numbers of cities which Cicasso will visit according to optimal choice of the route. Numbers of cities should be printed in the order that Cicasso will visit them. If there are multiple solutions, print any of them.

Example
Input
8 9
1 2
2 3
3 4
4 1
4 5
5 6
6 7
7 8
8 5
Output
2 1 8 7
Note

Let d(x, y) be the shortest distance between cities x and y. Then in the example d(2, 1) = 3, d(1, 8) = 7, d(8, 7) = 3. The total distance equals 13.

题目大意:

给你N个点,M条有向边,让你从中找到四个不重叠的点,使得其最短距离和最大。

输出这四个点的编号。


思路:


1、首先观察到点的个数和边的个数都不多,那么我们可以暴力的跑N次最短路,求得两点间距离,存入dis【i】【j】中,表示从i到j的最短路的长度。


2、那么接下来我们考虑如何寻找这四个点:

①如果我们暴力枚举的话,时间复杂度会高达O(n^4);明显是不可行的。

②那么我们此时可以考虑优化,我们枚举出三个点,作为第一个、第二个、和第三个点,那么其实贪心的去想,我们如果已经确定了这三个点的编号,那么最后一个点的编号一定是第三个点出发到的最远的那个和前两个点不重复的第一个点。而且维护一个点到其他点的最远距离时间复杂度O(n^2)就足够了,所以现在总时间复杂度降低了一个n:O(n^3);

③我们能够将第四个点通过上述过程优化找到的最主要原因是,其当前这个第四个点无论是哪个编号都不会影响前三个点的存在,如果我们现在枚举完前两个点,第三个点是第二个点的最远点,那么第四个点是第三个点的最远点,此时不一定就是最优解,因为第三个点到底是什么编号对第四个点产生了影响。所以我们显然不能直接这样枚举。我们继续考虑除了第四个点可以这样处理之外,还有哪个点可以这样处理?

④显然除了第四个点可以这样处理之外,我们可以选择第一个点。

那么此时我们O(n^2)枚举第二个和第三个点,第四个点是第三个点能够到达的最远点,那么同理,此时第二个点就是第一个点能够到达的最远点,那么我们O(n^2)预处理之后,再枚举即可。

⑤此时优化完毕,最终时间复杂度O(n^2);


3、注意这样一种情况,如果第二个点只是编号为zz的点能够到达的最远点,并且此时我们枚举出来的顺序为:第一个点zz,第二个点i,第三个点j,第四个点ss;

那么我们枚举到第二个点为i,第三个点为zz的时候,第二个点之前的那个第一个点就不是zz了,而是次远的点,所以这一块需要特殊处理一下即可:

我们将点i能够到达的点j距离进行从大到小排序存入vector,然后在枚举完第二个和第三个点的时候,我们第一个点可能不是zz,还有可能是次远点,所以这时候我们枚举一个最远点枚举一个次远点作为第一个点,同理,第四个点也枚举一个最远点,枚举一个次远点,维护最大即可。


Ac代码:

#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
struct node2
{
    int v,len;
}a[500085];
struct node
{
    int from;
    int to;
    int w;
    int next;
}e[50085];
int dis[3005][3005];
int vis[3005];
int head[3005];
int maxn[3005];
vector<int >mp[3005];
int maxn2[3005];
vector<int >mp2[3005];
int n,m,cont;
void add(int from,int to)
{
    e[cont].to=to;
    e[cont].w=1;
    e[cont].next=head[from];
    head[from]=cont++;
}
int cmp(node2 a,node2 b)
{
    return a.len>b.len;
}
void SPFA(int ss)
{
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)dis[ss][i]=0x3f3f3f3f;
    dis[ss][ss]=0;
    vis[ss]=1;
    queue<int >s;
    s.push(ss);
    while(!s.empty())
    {
        int u=s.front();
        s.pop();
        vis[u]=0;
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            int w=e[i].w;
            if(dis[ss][v]>dis[ss][u]+w)
            {
                dis[ss][v]=dis[ss][u]+w;
                if(vis[v]==0)
                {
                    vis[v]=1;
                    s.push(v);
                }
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        a[i].len=dis[ss][i];
        a[i].v=i;
    }
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        if(dis[ss][a[i].v]==0x3f3f3f3f)continue;
        mp[ss].push_back(a[i].v);
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        cont=0;
        int test=1;
        memset(maxn,0,sizeof(maxn));
        memset(maxn2,0,sizeof(maxn2));
        memset(head,-1,sizeof(head));
        for(int i=0;i<m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if(i==0&&x==575&&y==2010)test=0;
            add(x,y);
        }
        for(int i=1;i<=n;i++)
        {
            SPFA(i);
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                a[j].len=dis[j][i];
                a[j].v=j;
            }
            sort(a+1,a+n+1,cmp);
            for(int j=1;j<=n;j++)
            {
                if(dis[a[j].v][i]==0x3f3f3f3f)continue;
                mp2[i].push_back(a[j].v);
            }
        }
        int mxlen=0;
        int ans1,ans2,ans3,ans4;
        for(int j=1;j<=n;j++)
        {
            for(int k=1;k<=n;k++)
            {
                if(dis[j][k]==0x3f3f3f3f)continue;
                int flag=0;
                for(int zz=0;zz<mp2[j].size()&&zz<3;zz++)
                {
                    int i=mp2[j][zz];
                    for(int ss=0;ss<mp[k].size()&&ss<3;ss++)
                    {
                        int l=mp[k][ss];
                        if(i==j||i==k||i==l||j==k||j==l||k==l)continue;
                        else
                        {
                            flag=1;
                            if(mxlen<dis[i][j]+dis[j][k]+dis[k][l])
                            {
                                mxlen=dis[i][j]+dis[j][k]+dis[k][l];
                                ans1=i,ans2=j,ans3=k,ans4=l;
                                break;
                            }
                        }
                    }
                    if(flag==1)break;
                }
            }
        }
        //printf("%d\n",mxlen);
        printf("%d %d %d %d\n",ans1,ans2,ans3,ans4);

    }
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值