『题解』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;
}