(Luogu) P1119 灾后重建

传送门

题意:查询q次求一个村庄到另一个村庄的最短路,但这个题目又加了一个重建的条件,只有当一条路联通的两个村庄 (规定了村庄在第几天被修好) 都被修好这条路才可以通,所以点到点的最短距离又受制于时间t。

思路:查询是点到点在第t天的最短距离。首先这是多源最短路,各个村庄之间的最短距离我们都要知道,选用floyd食用最佳。接下来去解决时间t的问题。首先这个问题好的一点就是,村庄的重建好的时间是不下降的,查询的t也是不下降的,这样就very good了。floyd的第一层循环是枚举进行松弛的点。这里因为受制于t,所以我们接受一个查询,就将重建时间小于等于t的点都拿去松弛这一张图,但是因为查询的两个村庄可能还没有被重建,所以我们要判断一下,如果被重建过了而且被更新,那就输出最短距离,反之输出-1。

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<cstring>
#include<algorithm>
#include<limits.h>
using namespace std;
typedef long long ll;
const ll INF=0x3f3f3f3f;
const ll inf=-0x3f3f3f3f;
const ll maxn=200+5;
int dist[maxn][maxn],t[maxn];
int n,m,q;

int main() {
	scanf("%d%d",&n,&m);
	memset(dist,0x3f,sizeof(dist));
	for(int i=0; i<n; ++i) {
		scanf("%d",t+i);
		dist[i][i]=0;
	}
	int x,y,w;
	for(int i=1; i<=m; ++i) {
		scanf("%d%d%d",&x,&y,&w);
		dist[x][y]=dist[y][x]=w;
	}

	scanf("%d",&q);
	int xx,yy,tt,k=0;
	for(int i=0; i<q; ++i) {
		scanf("%d%d%d",&xx,&yy,&tt);
		while(t[k]<=tt&&k<n) {
			for(int i=0 ; i<n ; i++)
				for(int j=0; j<n ;j++) {
					dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
				}
			k++;
		}
		if(dist[xx][yy]==INF||t[xx]>tt||t[yy]>tt){
			cout<<-1<<endl;
		}
		else	cout<<dist[xx][yy]<<endl;
	}
	return 0;
}

 

一开始想用Dijkstra暴力出点到点的最小距离并用记忆化存储下来。但是就是不T也会MLE。但本菜鸡还是将其实现了出来,当然是“稻花香里说丰年,听取WA声一片”。

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<cstring>
#include<algorithm>
#include<limits.h>
using namespace std;
typedef long long ll;
const ll INF=0x3f3f3f3f;
const ll inf=-0x3f3f3f3f;
const ll maxn=200+5;
ll n,m,q,maxday=-1;
int t[maxn];
struct node {
	ll p;
	ll dis;
	node(ll np=0,ll ndis=0) {
		p=np,dis=ndis;
	}
	bool operator <(const node& x)const {
		return dis>x.dis;
	}
};
struct edge {
	ll id;
	ll to;
	ll w;
	edge(ll nid=0,ll nto=0,ll nw=0) {
		id=nid,to=nto,w=nw;
	}
};
vector<edge> e[maxn];
int dist[maxn][maxn][10005];
// i->j 第t天的最短路

bool vis[maxn];
void Dijkstra(int start) {
	for(int i=0; i<=n; ++i) {
		for(int k=0; k<=t[n-1]+1; ++k) {
			dist[start][i][k]=INF;
		}
	}

	memset(vis, false, sizeof(vis));
	dist[start][start][t[start]]=0;

	priority_queue<node> q;
	q.push(node(start,0));

	while(!q.empty()) {
		node tmp=q.top();
		q.pop();
		int np=tmp.p;
		if(vis[np])	continue;
		vis[np]=1;
		for(int i=0; i<e[np].size(); ++i) {
			edge ne=e[np][i];
			ll nto=ne.to;
			ll nw=ne.w;
			ll nday=max(t[nto],t[np]);
			if(dist[start][nto][nday]>dist[start][np][t[np]]+nw) {
				dist[start][nto][nday]=dist[start][np][t[np]]+nw;
//				cout<<start<<"->"<<nto<<" "<<nday<<" :"<<dist[start][nto][nday]<<endl;
				q.push(node(nto,dist[start][nto][nday]));
			}
		}
	}

	bool flag=false;
	for(int i=0; i<n; ++i) {
		flag=false;
		for(int k=0; k<=t[n-1]+1; ++k) {
			if(dist[start][i][k]!=INF) {
				flag=true;
			} else {
				if(flag) {
					if(dist[start][i][k]==INF) {
						dist[start][i][k]=dist[start][i][k-1];
					}
				}
			}
		}
	}
}
int main() {
	scanf("%lld%lld",&n,&m);
	for(int i=0; i<n; ++i) {
		scanf("%d",t+i);
	}
	ll x,y,w;
	for(int i=1; i<=m; ++i) {
		scanf("%lld%lld%lld",&x,&y,&w);//无向图建图
		e[x].push_back(edge(i,y,w));
		e[y].push_back(edge(i,x,w));
	}

	for(int i=0; i<n; ++i) {
		Dijkstra(i);

	}
	scanf("%lld",&q);
	int xx,yy,tt;
	for(int i=0; i<q; ++i) {
		scanf("%d%d%d",&xx,&yy,&tt);
		if(dist[xx][yy][tt]==INF) {
			cout<<-1<<endl;
		} else {
			cout<<dist[xx][yy][tt]<<endl;
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值