\(TLE\)代码
const int N=210;
vector<PII> g[N];
int tim[N];
int dist[N];
bool vis[N];
int n,m,q;
int dijkstra(int st,int ed,int limit)
{
if(tim[st]>limit || tim[ed]>limit) return -1;
memset(dist,0x3f,sizeof dist);
memset(vis,0,sizeof vis);
priority_queue<PII,vector<PII>,greater<PII> > heap;
dist[st]=0;
heap.push({0,st});
while(heap.size())
{
int t=heap.top().second;
heap.pop();
if(vis[t]) continue;
vis[t]=true;
for(int i=0;i<g[t].size();i++)
{
int j=g[t][i].fi,w=g[t][i].se;
if(tim[j] <= limit && dist[j] > dist[t]+w)
{
dist[j]=dist[t]+w;
heap.push({dist[j],j});
}
}
}
if(dist[ed] == INF) return -1;
return dist[ed];
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++) cin>>tim[i];
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
g[a].push_back({b,c});
g[b].push_back({a,c});
}
cin>>q;
while(q--)
{
int x,y,t;
cin>>x>>y>>t;
cout<<dijkstra(x,y,t)<<endl;
}
//system("pause");
}
注意输入条件
- \(第二行包含N个非负整数t_0, t_1,…, t_{N-1},表示了每个村庄重建完成的时间,数据保证了t_0 ≤ t_1 ≤ … ≤ t_{N-1}\)
即每个村庄的重建完成时间按村庄编号递增
观察到数据范围
- \(N≤200\),不免联想到\(O(n^3)\)的最短路floyd算法
floyd算法本质:动态规划,d[k,i,j]表示从i号顶点到j号顶点只经过前k号点的最短距离。
我们再回头看题意:
所有的边全部给出,按照时间顺序更新每一个可用的点(即修建好村庄),对于每个时间点进行两点之间询问,求对于目前建设的所有村庄来说任意两点之间的最短路。
不正好就是Floyd算法中使用前k个节点更新最短路的思维吗?
出题人还是很良心的,保证所有的数据都是用时间顺序给出的,所以我们只用读取+操作就可以了,不用再存储+排序。
时间复杂度:\(O(q+n^3)\)
const int N=210;
int g[N][N];
int tim[N];
int n,m,q;
void floyd(int k)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++) cin>>tim[i];
memset(g,0x3f,sizeof g);
for(int i=0;i<n;i++) g[i][i]=0;
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
g[a][b]=g[b][a]=min(g[a][b],c);
}
cin>>q;
int k=0;
while(q--)
{
int x,y,t;
cin>>x>>y>>t;
while(k<n && tim[k] <= t)
{
floyd(k);
k++;
}
if(g[x][y] == INF || tim[x] > t || tim[y] > t) puts("-1");
else cout<<g[x][y]<<endl;
}
//system("pause");
}