CF666B 题解
一张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;
}

浙公网安备 33010602011771号