对于dij与SPFA的疑惑
查看原帖
对于dij与SPFA的疑惑
635829
D_FANG楼主2024/11/2 17:56

在OI Wiki上,对于dij算法的证明有说到 在所有边权值非负的前提下,Dijkstra 算法的正确性 而我在本题使用二分ans+最短路的时候,dij跑出的答案是错的,而只有SPFA跑的是对的,对此疑惑不解,求证明dij的不可用性(玄关)

二分+dij:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1e4,inf=1e9+7;
struct two{
	int d,u;
};
bool operator<(const two x,const two y){
	return x.d<y.d;
}
bool operator>(const two x,const two y){
	return x.d>y.d;
}
struct heap{
	two a[20*N];
	int n;
	two top(){
		return a[1];
	}
	void push(two x){
		a[++n]=x;
		int p=n;
		while (p!=1){
			if (a[p]<a[p/2]){
				swap(a[p],a[p/2]);
				p/=2;
			}
			else break;
		}
	}
	void pop(){
		a[1]=a[n];
		--n;
		int pp,p=1;
		while ((p<<1)<=n){
			pp=(p<<1);
			if (pp+1<=n&&a[pp+1]<a[pp]) ++pp;
			if (a[p]<a[pp]){
				swap(a[p],a[pp]);
				p=pp;
			}
			else break;
		}
	}
	bool empty(){
		return n==0;
	}
	void memsets(){
		n=0;
	}
}t;
struct rec{
	int e,nex,d;
}z[2*N];
int en,fi[N];
struct pai{
	int s,e,d;
}a[N];
bool cmp(const pai x,const pai y){
	return x.d<y.d;
}
void add(int s,int e,int d){
	++en;
	z[en].d=d;
	z[en].e=e;
	z[en].nex=fi[s];
	fi[s]=en; 
}
int n,p,k;
int dp[N];
bool vis[N];
bool dij(int d,int st,int ed){
	t.memsets();
	for (int i=1;i<=n;++i) fi[i]=0; 
	en=0;
	for (int i=1;i<=p;++i){
		if (a[i].d<=d){
			add(a[i].s,a[i].e,0);
			add(a[i].e,a[i].s,0);
		}
		else {
			add(a[i].s,a[i].e,1);
			add(a[i].e,a[i].s,1);
		}
	}
	for (int i=1;i<=n;++i){
		dp[i]=inf;vis[i]=false;
	}
	dp[st]=0;
	two x,y;
	x.u=st;x.d=0;
	t.push(x);
	while (t.empty()==false){
		x=t.top();
		t.pop();
		if (vis[x.u]==true) continue;
		vis[x.u]=true;
		for (int i=fi[x.u];i!=0;i=z[i].nex){
		//	printf("x.u=%d dp[z[i].e]=%d z[i].e=%d dp[x.u]=%d z[i].d=%d\n",x.u,dp[z[i].e],z[i].e,dp[x.u],z[i].d);
			if (dp[z[i].e]>dp[x.u]+z[i].d){
				dp[z[i].e]=dp[x.u]+z[i].d;
				y.u=z[i].e;y.d=dp[z[i].e];
				t.push(y);
			}
		}
	}
	return (dp[ed]<=k)?true:false;
}
int work(){
	int l=0,r=p+1,mid;
	while (l<r){
		mid=(l+r)>>1;
		if (dij(a[mid].d,1,n)==true) r=mid;
		else l=mid+1;
	}
	return l;
}
int ans;
int main(){
//	freopen("1.out","w",stdout);
	scanf("%d%d%d",&n,&p,&k);
	for (int i=1;i<=p;++i){
		scanf("%d%d%d",&a[i].s,&a[i].e,&a[i].d);
	}
	a[0].d=0;
	sort(a+1,a+1+p,cmp);
	ans=work();
	if (ans==p+1) printf("-1");
	else printf("%d",a[ans].d);
	return 0;
} 

二分+SPFA:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1e4,inf=1e9+7;
struct two{
	int d,u;
};
queue<two>t;
struct rec{
	int e,nex,d;
}z[2*N];
int en,fi[N];
struct pai{
	int s,e,d;
}a[N];
bool cmp(const pai x,const pai y){
	return x.d<y.d;
}
void add(int s,int e,int d){
	++en;
	z[en].d=d;
	z[en].e=e;
	z[en].nex=fi[s];
	fi[s]=en; 
}
int n,p,k;
int dp[N];
bool vis[N];
bool dij(int d,int st,int ed){
	for (int i=1;i<=n;++i) fi[i]=0; 
	en=0;
	for (int i=1;i<=p;++i){
		if (a[i].d<=d){
			add(a[i].s,a[i].e,0);
			add(a[i].e,a[i].s,0);
		}
		else {
			add(a[i].s,a[i].e,1);
			add(a[i].e,a[i].s,1);
		}
	}
	for (int i=1;i<=n;++i){
		dp[i]=inf;vis[i]=false;
	}
	dp[st]=0;
	two x,y;
	x.u=st;x.d=0;
	t.push(x);
	vis[st]=true;
	while (t.empty()==false){
		x=t.front();
		t.pop();
		vis[x.u]=false;
		for (int i=fi[x.u];i!=0;i=z[i].nex){
		//	printf("x.u=%d dp[z[i].e]=%d z[i].e=%d dp[x.u]=%d z[i].d=%d\n",x.u,dp[z[i].e],z[i].e,dp[x.u],z[i].d);
			if (dp[z[i].e]>dp[x.u]+z[i].d){
				dp[z[i].e]=dp[x.u]+z[i].d;
				if (vis[z[i].e]==true) continue;
				y.u=z[i].e;y.d=dp[z[i].e];
				vis[z[i].e]=true;
				t.push(y);
			}
		}
	}
	return (dp[ed]<=k)?true:false;
}
int work(){
	int l=0,r=p+1,mid;
	while (l<r){
		mid=(l+r)>>1;
		if (dij(a[mid].d,1,n)==true) r=mid;
		else l=mid+1;
	}
	return l;
}
int ans;
int main(){
//	freopen("1.out","w",stdout);
	scanf("%d%d%d",&n,&p,&k);
	for (int i=1;i<=p;++i){
		scanf("%d%d%d",&a[i].s,&a[i].e,&a[i].d);
	}
	a[0].d=0;
	sort(a+1,a+1+p,cmp);
	ans=work();
	if (ans==p+1) printf("-1");
	else printf("%d",a[ans].d);
	return 0;
} 
2024/11/2 17:56
加载中...