World Tour
题目链接: World Tour
题意:
给你一张有向图,叫你给出四个点的序列,使得这四个点依次间的最短路之和最大。
分析:
n到3000,所以直接枚举四个点肯定超时,因此可以枚举b、c两个点,然后BFS预处理出能到b的最远的3个点,和c能到的最远的3个点。
之所以是3个点是因为,有可能备选点会和已定点重合,例如abc都定好了,然后d的备选是a、b,那就漏情况了,所以要备选3个点。
代码:
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define maxn 5010
#define maxv 3010
const int inf=0x3f3f3f3f;
struct edge
{
int v,next;
} e[maxn];
struct node
{
int index,len;
node() {}
node(int x,int y):index(x),len(y) {}
bool operator < (const node&A)
{
if(len==A.len)
return index<A.index;
return len<A.len;
}
} longestTo[maxv][3],longestFrom[maxv][3];
int dis[maxv][maxv],first[maxv];
bool inq[maxv];
int n,m,len;
void UpdateFrom(node u,node v)//从u能到的最远的点
{
longestFrom[u.index][0]=v;
sort(longestFrom[u.index],longestFrom[u.index]+3);
}
void UpdateTo(node u,node v)//能到u的最远的点
{
v.len=u.len;
longestTo[u.index][0]=v;
sort(longestTo[u.index],longestTo[u.index]+3);
}
void bfs(int x)//对每一个点寻找离它最远的三个点
{
queue<node>Q;
node st(x,0);
Q.push(st);
inq[x]=true;
while(!Q.empty())
{
node u=Q.front();
Q.pop();
for(int i=first[u.index]; ~i; i=e[i].next)
{
node v(e[i].v,u.len+1);
if(!inq[v.index])
{
inq[v.index]=true;
UpdateFrom(st,v);//从st能到的最远的点
UpdateTo(v,st);//能到v的最远的点
dis[st.index][v.index]=v.len;
Q.push(v);
}
}
}
}
void add_edge(int u,int v)//邻接表存边
{
e[len].v=v,e[len].next=first[u];
first[u]=len++;
}
int main()
{
memset(first,-1,sizeof(first));
memset(dis,inf,sizeof(dis));
scanf("%d%d",&n,&m);
int u,v;
len=0;
for(int i=0; i<m; ++i)
{
scanf("%d%d",&u,&v);
if(u==v)
continue;
add_edge(u,v);
}
for(int i=1; i<=n; ++i)
{
memset(inq,false,sizeof(inq));
bfs(i);
}
int ans[4]= {0};
int tot=0;
for(int b=1; b<=n; ++b)//枚举两个点,寻找另外两个
for(int c=1; c<=n; ++c)
for(int i=2; ~i; --i)
for(int j=2; ~j; --j)
{
int a=longestTo[b][i].index;
int d=longestFrom[c][j].index;
if(a==b||a==c||a==d||b==c||b==d||c==d)
continue;
if(dis[a][b]==inf||dis[b][c]==inf||dis[c][d]==inf)
continue;
int tmp=dis[a][b]+dis[b][c]+dis[c][d];
if(tmp>tot)
{
tot=tmp;
ans[0]=a;
ans[1]=b;
ans[2]=c;
ans[3]=d;
}
}
for(int i=0; i<4; ++i)
printf("%d ",ans[i]);
return 0;
}
总结:很强大的一道题,思路和代码都给了我很大启发。better
一开始我的想法是,先用最短路求出每两个点之间的最短距离,然后DFS枚举4个点。。。想想都超时啊。
参考博客:
初涉_代码世界