这道题目一开始我的思路就是错了,前前后后挣扎了n个小时。。。开始的想法是dijkstra,通过二分枚举高度差。但是发现一个问题,就是因为dijkstra里面优先选择的是短的路。我直接二分高度差,是有两个限制条件。然后就想到spfa,后来仔细想了想还是不行。。。最后用dfs了,才100个点嘛,感觉稳了,结果又tle。。。。。。。
开了别人的题解一眼,恍然大悟。有两个限制条件(用于选择)的最短路怎么能求呢?
所以本题的思路是,枚举任意的两个点,两个点的高度分别当作是low和up
另外注意判断1==N的情况。。。真是无力吐槽了。。。
AC的代码
//通过枚举最小边还是不行
#include <bits/stdc++.h>
using namespace std;
#define res register int
#define ll long long
#define inf 0x3f3f3f3f
const int maxn=105;
int N,M,h[maxn];
int G[maxn][maxn];
int dis[maxn],vis[maxn];
int low,up;
int result;
struct Node{
int low,up;
}node[maxn*maxn];
bool operator<(const Node a,const Node b){
if(a.up-a.low!=b.up-b.low)
return a.up-a.low<b.up-b.low;
else
return a.up<b.up;
}
bool spfa()
{
int flag=0;
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
queue<int> q;
q.push(1);
vis[1]=1;
dis[1]=0;
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=0;
for(res i=1;i<=N;i++){
int y=i;
if(y!=x&&dis[y]>dis[x]+G[x][y]&&low<=h[y]&&h[y]<=up){
dis[y]=dis[x]+G[x][y];
if(N==y){
result=min(result,dis[N]);
flag=1;
}
if(!vis[y]){
q.push(y);
vis[y]=1;
}
}
}
}
if(0==flag) return false;
else return true;
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
//init
memset(vis,0,sizeof(vis));
scanf("%d%d",&N,&M);
for(res i=1;i<=N;i++){
scanf("%d",&h[i]);
for(res j=1;j<=N;j++){
if(i!=j) G[i][j]=G[j][i]=inf;
else G[i][j]=0;
}
}
int a,b,v;
for(res i=1;i<=M;i++){
scanf("%d%d%d",&a,&b,&v);
if(v<G[a][b]) G[a][b]=G[b][a]=v;
}
//init
int ans=1;
for(res i=1;i<=N;i++){
for(res j=1;j<=N;j++){
if(i!=j){
node[ans].up=max(h[i],h[j]);
node[ans++].low=min(h[i],h[j]);
}
}
}
node[ans].low=h[1];
node[ans++].up=h[1];
sort(node+1,node+1+ans);
int i,temp=-1;
int flag=0,pre=inf;
result=inf;
node[0].low=node[0].up=-1;
for(i=1;i<ans;i++){
if(node[i].up==node[i-1].up&&node[i].low==node[i-1].low) continue;
if(flag&&node[i].up-node[i].low>pre) break;
low=node[i].low,up=node[i].up;
if(low>h[1]||low>h[N]||up<h[1]||up<h[N]) continue;
if(spfa()){
flag=1;
pre=node[i].up-node[i].low;
}
}
if(1==N) printf("%d %d\n",0,0);
else printf("%d %d\n",pre,result);
}
return 0;
}
tle的dfs
#include <bits/stdc++.h>
using namespace std;
#define res register int
#define ll long long
#define inf 0x3f3f3f3f
const int maxn=105;
int N,M,h[maxn];
int G[maxn][maxn];
int dis[maxn],vis[maxn];
int Max[maxn],Min[maxn];
int result,flag=0;
void dfs(int n,int H,int Maxh,int Minh){
if(n==N){
result=min(dis[N],result);
flag=1;
return;
}
for(res i=1;i<=N;i++){
if(i!=n&&!vis[i]&&dis[i]>dis[n]+G[i][n]&&max(Maxh,h[i])-min(Minh,h[i])<=H){
int temp=dis[i];
dis[i]=dis[n]+G[i][n];
vis[i]=1;
dfs(i,H,max(Maxh,h[i]),min(Minh,h[i]));
vis[i]=0;
dis[i]=temp;
}
}
return;
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
//init
result=inf;
scanf("%d%d",&N,&M);
int Maxh=0,Minh=inf;
for(res i=1;i<=N;i++){
scanf("%d",&h[i]);
Maxh=max(Maxh,h[i]);Minh=min(Minh,h[i]);
for(res j=1;j<=N;j++){
if(i!=j) G[i][j]=G[j][i]=inf;
else G[i][j]=0;
}
}
int a,b,c;
for(res i=1;i<=M;i++){
scanf("%d%d%d",&a,&b,&c);
if(c<G[a][b]) G[a][b]=G[b][a]=c;
}
//init
int l=abs(h[N]-h[1]),r=Maxh-Minh;
while(l<=r){
int mid=(l+r)>>1;
result=inf;
memset(vis,0,sizeof(vis));
memset(dis,inf,sizeof(dis));
dis[1]=0;
vis[1]=1;
flag=0;
dfs(1,mid,h[1],h[1]);
if(flag){
r=mid-1;
}else{
l=mid+1;
}
}
printf("%d %d\n",l,result);
}
return 0;
}