题意:
有 n 个城市,q 次询问.
给出每个城市的危险度 r 和 城市的邻接矩阵.
每次询问给出 u、v、w,求从 u 到 v 且不经过其他危险度超过 w 的城市的最短路.
题解:
floyd 变形
我队友一开始想的是每次加点然后跑dij,但是肯定会超时
我想的是给出起点和终点,选出满足条件的城市,然后用这些城市去更新最短路径
在本题中就是利用floyd来做,一半来说第三层循环是枚举中间变量k,我们将其提到最外面,对于每一次询问,都有一个危险值上限w,我们根据这个w,筛选出危险值小于w的所有点(即城市),然后依次跑更新操作,等全部跑完,此时询问的两个城市之间的路径长度即为最短路且所有城市危险值不会超过w
方法二:
我还看到一个做法,
dp[k][i][j]表示最大权值为所有权值k大的i到j的最短路距离
对城市的危险值排序,依次加点更新不同层次的最短路
最后读入直接输出
我感觉两个方法本质应该差不多
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=300;
const int maxm=2e4+9;
int dis[maxn][maxn];
struct node{
int u,v,w;
int id;
}qq[maxm];
struct nod
{
int id,r;
}a[maxn];
int ans[maxm];
bool cmp(node a,node b)
{
return a.w<b.w;
}
bool cmp1(nod a,nod b)
{
return a.r<b.r;
}
int main()
{
int t;
cin>>t;
for(int tt=1;tt<=t;tt++)
{
//memset(dis,0x3f,sizeof dis);
//memset(ans,0,sizeof ans);
int n,q;
scanf("%d%d",&n,&q);
//cin>>n>>q;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].r);
//cin>>a[i].r;
a[i].id=i;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&dis[i][j]);
//cin>>dis[i][j];
}
}
for(int i=1;i<=q;i++)
{
int u,v,w;
scanf("%d%d%d",&qq[i].u,&qq[i].v,&qq[i].w);
//cin>>qq[i].u>>qq[i].v>>qq[i].w;
qq[i].id=i;
}
sort(qq+1,qq+1+q,cmp);
sort(a+1,a+1+n,cmp1);
int cur=1;
for(int xx=1;xx<=q;xx++)//q*n*n*?n
{
while(a[cur].r<=qq[xx].w&&cur<=n)
{
int k=a[cur].id;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);
}
}
cur++;
}
ans[qq[xx].id]=dis[qq[xx].u][qq[xx].v];
}
// for(int i=1;i<=n;i++)
// {
//
// for(int j=i;j<=n;j++)
// {
// if(i==j)
// {
// dis[i][j]=0;
// dis[j][i]=0;
// }
// for(int k=1;k<=n;k++){
// //if()
// dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);
// }
// }
// }
printf("Case #%d:\n",tt);
for(int i=1;i<=q;i++)
{
cout<<ans[i]<<endl;
}
}
return 0;
}
第二个方法:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
int dp[310][310][310];
int has[310];int dan[310];
int num[310];
bool cmp(int a,int b){
return dan[a]<dan[b];
}
int main(){
int t;
int cur=1;
scanf("%d",&t);
while(t--){
int n,m;
scanf("%d%d",&n,&m);
memset(dp,0x3f3f3f3f,sizeof(dp));
int cnt=1;
for(int i=1;i<=n;i++){
scanf("%d",&dan[i]);
num[i]=i;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&dp[i][j][0]);
sort(num+1,num+1+n,cmp);
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dp[i][j][k]=min(dp[i][j][k-1],dp[i][num[k]][k-1]+dp[num[k]][j][k-1]);
}
}
}
printf("Case #%d:\n",cur++);
while(m--){
int st,ed,w;
scanf("%d%d%d",&st,&ed,&w);
int ans=0;
for(int i=1;i<=n;i++){
if(dan[num[i]]<=w) ans=i;
}
printf("%d\n",dp[st][ed][ans]);
}
}
}