假期计划

假期计划

由于要考虑相邻城市之间的中转点不超过 \(k\)(即所经过边数不超过 \(k+1\)),所以首先要预处理出 \(dis[i][j]\),即两两之间的点的距离,可以 bfs \(n\) 次解决。然后就是考虑怎么进行枚举了。首先如果直接枚举四个点显然不可行,时间复杂度是 \(O(n^4)\),应该想到一个技巧:折半枚举。假设点依次是 \(1->A->B->C->D->1\),可以先考虑弄 \(1->A->B\),再弄 \(1->C->D\),然后想办法拼接起来。

接下来是重点:对于每个点,都记录一个从 \(1\) 到某个中间点再到它的贡献,然后取贡献前三名的中间点。然后枚举 \(B,D\) 两点,取它们存储的中转点 \(A,C\) 进行两两组合,应该有 \(3\times 3=9\) 种情况。

这个做法的确很好,但为什么取贡献前三名的点呢?

假如留一个,万一 \(B,D\)\(A,C\) 相等,显然不合法。

假如留两个,如下图

image-20230520215630893

上图中,无论 \(A,C\) 怎么组合,都会只有 \(2\sim 3\) 个不同的点。

留三个,如下图

image-20230520215831741

就算有 \(B,C\),其他的都相同,也可以构造出 \(1->E->B->F->D->1\)。上述的是最坏情况,如果二者其他不相同,那么更加可行了。

思路还是有点难想的,就当作刷新一下自己的认知。

代码需要注意,图可能不连通

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define Ls(i,l,r) for(int i=l;i<=r;++i)
#define Rs(i,l,r) for(int i=r;i>l;--i)
#define L(i,l) for(int i=0;i<l;++i)
typedef long long ll;
const int N=2510,M=20010,INF=0x3f3f3f3f;
int n,m,k,h[N],e[M],ne[M],idx,dis[N][N],q[N];
ll d[N],tu[3][N],res;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void bfs(int s,int dis[]){
    memset(dis,0x3f,N*4);
    dis[s]=0;
    int hh=0,tt=0;
    q[tt++]=s;
    while(hh<tt){
        int u=q[hh++];
        for(int i=h[u];~i;i=ne[i]){
            int v=e[i];
            if(dis[v]==INF){
                dis[v]=dis[u]+1;
                q[tt++]=v;
            }
        }
    }
}
int main(){
    memset(h,-1,sizeof h);
    scanf("%d%d%d",&n,&m,&k);
    ++k;
    Ls(i, 2, n)scanf("%lld",d+i);
    while(m--){
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);
    }
    Ls(i, 1, n)bfs(i,dis[i]);
    Ls(i, 2, n)
        Ls(j, 2, n){
            if(i!=j&&dis[1][i]<=k&&dis[i][j]<=k){
                ll v=d[i];
                if(v>=d[tu[0][j]])
                    tu[2][j]=tu[1][j],tu[1][j]=tu[0][j],tu[0][j]=i;
                else if(v>=d[tu[1][j]])
                    tu[2][j]=tu[1][j],tu[1][j]=i;
                else if(v>=d[tu[2][j]])tu[2][j]=i;
            }
        }
    ll a[3],b[3];
    Ls(i, 2, n)
        Ls(j, 2, n){
            if(i==j||dis[i][j]>k)continue;
            int cnta=0,cntb=0;
            L(k, 3)if(tu[k][i]&&tu[k][i]!=j)a[cnta++]=tu[k][i];
            L(k, 3)if(tu[k][j]&&tu[k][j]!=i)b[cntb++]=tu[k][j];
            L(k, cnta)
                L(l, cntb)
                    if(a[k]!=b[l]){
                        ll tmp=d[a[k]]+d[i]+d[j]+d[b[l]];
                        if(tmp>res)res=tmp;
                    }
        }
    printf("%lld",res);
    return 0;
}
posted @ 2023-05-20 22:00  wscqwq  阅读(9)  评论(0编辑  收藏  举报