复制代码

CF666B 题解

CF666B World Tour
题意

一张n个点m条边的有向图,每条边的权值相同.你要找4个点a,b,c,d,使得a->b->c->d的最短路最长(a,b,c,d之间要有路),输出一组解.

输入

8 9
1 2
2 3
3 4
4 1
4 5
5 6
6 7
7 8
8 5

输出
2 1 8 7
分析
首先预处理每个点到其他点的最短路。
然后直接枚举复杂度O(\(n^4\))显然会超时,对于多元组枚举中间值会更好。
题目要求4个,那么我们枚举B,C,
A由B确定,D由C确定,那么枚举几个呢。
答案是三个,理由:已经确定了B,C ,保证没有重复,再确定A。D的值不会包括A,B。C不用管,因为是C-D要有距离,D肯定不能选和C一样的。
要求最大,我们就根据到每个点的距离排序,记录一下。
这下复杂度是O(\(9n^2\)),不会超时。
代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <cstring>
#include <vector>
using namespace std;
typedef long long ll;
const int N=4e3;
struct  edge{
    int from;
    int to;
    int dis;
    int next;
}e[N<<5];
vector< pair<int,int> > a[N],b[N];
// pair <距离,编号>
int ans[4];
int minn,A,B,C,D;
bool cmp(const pair<int,int> a,const pair<int,int> b)
{
    return a.first > b.first;
}
int head[N<<5],cnt;
int n,m,u,v;
void add(int u,int v,int w)
{
     ++cnt;
     e[cnt].from = u;
     e[cnt].to = v;
     e[cnt].dis = w;
     e[cnt].next = head[u];
     head[u] = cnt;
}
int diss[N][N];
int mapp[N<<5];
bool vis[N<<5];
queue<int> q;
void SPFA(int u)
{
    memset(mapp,0x3f,sizeof(mapp));
    memset(vis,0,sizeof(vis));
    mapp[u] = 0; vis[u] = true;
    q.push(u);
    while(!q.empty())
    {
       int x = q.front();
       vis[x] = false;
       q.pop();
       for(int i=head[x];i;i=e[i].next)
       {
           int y = e[i].to;
           if(mapp[y] > mapp[x] + e[i].dis)
           {
               mapp[y] = mapp[x] + e[i].dis;
               if(vis[y] == false)
               {
                  vis[y] = true;
                  q.push(y);
               }
           }
       }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>u>>v;
        add(u,v,1);
    }
    for(int i=1;i<=n;i++)
    {
        SPFA(i);//
        for(int j=1;j<=n;j++)
        diss[i][j] = mapp[j];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(diss[i][j] == 1061109567) diss[i][j] = -1;//不连通时设为-1
            //cout<<diss[i][j]<<" ";
            if(diss[j][i] == 1061109567) diss[j][i] = -1;
            a[i].push_back(make_pair(diss[j][i],j));//到i
            b[i].push_back(make_pair(diss[i][j],j));//到j
        }
        sort(a[i].begin(),a[i].end(),cmp);
        sort(b[i].begin(),b[i].end(),cmp);
        //cout<<endl;
    }
    for(int i=1;i<=n;i++)//枚举B
    {
        for(int j=1;j<=n;j++)//枚举C
        {
            if(i == j || diss[i][j] == -1) continue;
            for(int k=0;k<3;k++)//枚举A(到B最大的三个)
            {
                int pos = a[i][k].second;
                if(pos == i || pos == j) continue;
               for(int w=0;w<3;w++)//枚举D(C - D 最大的三个)
               {
                   int site = b[j][w].second;
                   if(site == pos || site == i || site == j) continue;
                   //这里不用再判,因为从大到小排序已经自动忽略不连通的-1了
                   if(minn < (diss[pos][i] + diss[i][j] + diss[j][site]))
                   {
                       minn = (diss[pos][i] + diss[i][j] + diss[j][site]);
                       ans[0] = pos;
                       ans[1] = i;
                       ans[2] = j;
                       ans[3] = site;
                   }
               }
            }
        }
    }
    for(int i=0;i<4;i++)
    cout<<ans[i]<<" ";
    //cout<<minn;
    return 0;
}
posted @ 2021-09-29 11:35  Elgina  阅读(335)  评论(2)    收藏  举报