『题解』SPOJ SP18966 VACATION - Vacation Planning

题目传送门

题目大意

给定一张 \(n(1 \le n \le 200)\) 个顶点的有向带权图,\(m(1 \le m \le 2 \times 10^4)\) 条从 \(u_i\) 指向 \(v_i\) 权值为 \(w_i\) 的边。

其中前 \(k(1 \le k \le 100,k \le n)\) 个顶点为枢纽。

现有 \(q(1 \le q \le 10^4)\) 个请求,每个请求给出起始点与终点。

请计算:

  • 有多少个请求满足从起始点开始有至少一条路径,穿过了至少一个枢纽到达终点。

  • 在这些满足要求的请求中,所需的最小开销之和。

思路

\(1 \le n \le 200\),又有多个询问,显然可以 Floyd。

对于穿过枢纽这项要求,可以在每次询问时遍历所有枢纽,求从起点到当前枢纽,再到终点的最短路径的最小值即可。

这个最小值 \(minn\) 最初设为正无穷,若遍历所有枢纽后还是正无穷,则说明当前请求不满足要求。

时间复杂度 \(\mathcal{O}(n^3+qk)\),记得开 long long。

代码

#include <iostream>
#include <cstring>
using namespace std;
template<typename T=int>
inline T read(){
    T X=0; bool flag=1; char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-') flag=0; ch=getchar();}
    while(ch>='0' && ch<='9') X=(X<<1)+(X<<3)+ch-'0',ch=getchar();
    if(flag) return X;
    return ~(X-1);
}

typedef int ll;
const ll N=2e2+5,inf=0x3f3f3f3f3f3f3f3f;
int n,m,k,q,u,v,w;
ll minn,cnt,ans;
ll g[N][N];

void floyd(){
    for(int k=1; k<=n; k++)
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
}

int main(){
    memset(g,0x3f,sizeof(g));
    n=read(),m=read(),k=read(),q=read();
    for(int i=1; i<=n; i++)
        g[i][i]=0;
    while(m--){
        u=read(),v=read(),w=read();
        g[u][v]=w;
    }
    floyd();
    while(q--){
        u=read(),v=read();
        minn=inf;
        for(int i=1; i<=k; i++)
            if(g[u][i]+g[i][v]>0)
                minn=min(minn,g[u][i]+g[i][v]);
        if(minn!=inf){
            cnt++;
            ans+=minn;
        }
    }
    printf("%lld\n%lld\n",cnt,ans);
    return 0;
}
posted @ 2022-07-19 11:58  仙山有茗  阅读(24)  评论(0编辑  收藏  举报