LuoguP1119 灾后重建
- Dijkstra 做法:TLE 3个点,70pts (O2) , 复杂度 \(O(n^3\ log\ m)\), \(\Theta(n^3\ log\ m\ +\ Qn)\) 可优化至 \(\Theta(\ n^3\ log\ m\ +\ n)\), 懒得写了。
代码:
//Dijkstra Version
#include<stdio.h>
#include<queue>
#include<vector>
#include<cstring>
//#pragma GCC optimize(2)
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N=205,INF=(1<<30)-1+(1<<30);
int t[N],n,m,dist[N][N][N];
bool reb[N],vis[N]={};
struct edge{
int v,w;
edge(int v,int w):v(v),w(w){}
};vector<edge>e[N];
struct node{
int u,dis;
node(int u,int dis):u(u),dis(dis){}
bool operator <(const node &a)const{return dis>a.dis;}
};
void Dijkstra(int s,int time){
memset(vis, 0, sizeof(vis));
for(int i=1;i<=n;i++)dist[time][s][i]=dist[time][i][s]=INF;
if(!reb[s])return;
dist[time][s][s]=0;
priority_queue<node>q;
q.push(node(s,0));
while(!q.empty()){
int u=q.top().u;q.pop();//printf("%d %d\n",u,vis[u]);
int len=e[u].size();
if(!vis[u]){
vis[u]=1;
for(int i=0;i<len;i++){
int v=e[u][i].v,w=e[u][i].w;
if(!vis[v]&&reb[v]&&dist[time][s][v]>dist[time][s][u]+w){
dist[time][s][v]=dist[time][v][s]=dist[time][s][u]+w;
q.push(node(v,dist[time][s][v]));
}
}
}
}
}
int normalfind(int x){
int i,sum=0;
for(i=1;i<=n;i++){
if(t[i]>x)break;
if(t[i]==t[i+1]&&i<n)sum--;
}return sum+i-1;
}
signed main(){
// freopen("P1119_2.in","r",stdin);
// freopen("a.out","w",stdout);
int u,v,w,x,y,z;
n=read(),m=read();
for(int i=1;i<=n;i++)t[i]=read();
for(int i=1;i<=m;i++){
u=read(),v=read(),w=read();u++,v++;
e[u].push_back(edge(v,w));
e[v].push_back(edge(u,w));
}
for(int i=1,top=0;i<=n;i++){
top++;
reb[i]=1;
while(i<n&&t[i]==t[i+1])reb[++i]=1;
for(int j=1;j<=n;j++)
Dijkstra(j,top);
}
int q;
q=read();
while(q--){
x=read(),y=read(),z=read();x++,y++;
z=normalfind(z);
if(z==0||dist[z][x][y]>=INF-3)puts("-1");
else printf("%d\n",dist[z][x][y]);
}
return 0;
}
- 正解 Floyd 做法 复杂度 \(O(n^3)\), \(\Theta(n^3\ +\ n)\)
代码很好理解,如果看了下面代码还没懂可以戳题解 题解
关键点是 t 是不下降序列,询问给出的 t 也是不下降的,所以容易想到顺序求解。但是题目完全可以给你乱序的,这就要离线排序做了。
AC代码:
//Floyd Version
#include <bits/stdc++.h>
using namespace std;
const int INF=1e8,N=210;
int f[N][N],lim;
int n,m,q,t[N],u,v,w,x,y,times;
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
f[i][j]=INF;
for(int i=0;i<n;i++)scanf("%d",&t[i]),f[i][i]=0;
while(m--)scanf("%d%d%d",&u,&v,&w),f[u][v]=f[v][u]=w;
scanf("%d",&q);
while(q--){
scanf("%d%d%d",&u,&v,&w);
for(int k=lim;k<n&&t[k]<=w;k++,lim++)
//在线顺序求解,一个一个放入
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
if (t[u]<=w&&t[v]<=w&&f[u][v]<INF)
printf("%d\n",f[u][v]);
else puts("-1");
}
return 0;
}

浙公网安备 33010602011771号