【bzoj1975】[Sdoi2010]魔法猪学院 A*

时间:2022-09-07 13:22:37

A*算法还是比较有意思的,本来以为就是个搜索加减枝,现在看来是有复杂度保证的

我们到一个状态后,处理出当前状态的估价函数,每次选择估价函数最小的来更新

估价函数g(n)的选取,若g(n)=实际值时,是有时间复杂度保证的,并且每次得到的答案一定是当前的最优解

bfs就是一个特殊的A*算法

这里的估价函数g(i)可以设置成为从T点到i点的最短路,每次用优先队列选估价最小的那个点更新


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
#define maxn 5010
#define maxm 201000
#define inf 1e12

using namespace std;

struct yts
{
	int now;
	double g;
};

double dis[maxn];
int q[maxn];
bool vis[maxn];

bool operator<(yts x,yts y)
{
	return x.g+dis[x.now]>y.g+dis[y.now];
}

priority_queue<yts> Q;

int head[maxn],to[maxm],next[maxm];
double len[maxm],Len[maxm];
int Head[maxn],To[maxm],Next[maxm];
int n,m,num,ans,x,y,S,T,Num;
double e,z;

void addedge(int x,int y,double z)
{
	num++;to[num]=y;len[num]=z;next[num]=head[x];head[x]=num;
}

void add(int x,int y,double z)
{
	Num++;To[Num]=y;Len[Num]=z;Next[Num]=Head[x];Head[x]=Num;
}

void spfa()
{
	for (int i=S;i<=T;i++) dis[i]=inf;
	dis[T]=0;vis[T]=1;q[1]=T;
	int l=0,r=1;
	while (l!=r)
	{
		l++;if (l==maxn) l=0;
		int x=q[l];
		for (int p=Head[x];p;p=Next[p])
		  if (dis[x]+Len[p]<dis[To[p]])
		  {
		  	dis[To[p]]=dis[x]+Len[p];
		  	if (!vis[To[p]])
		  	{
		  		r++;if (r==maxn) r=0;
		  		vis[To[p]]=1;q[r]=To[p];
		  	}
		  }
		vis[x]=0;
	}
}

void Astar()
{
	Q.push((yts){S,0});
	while (!Q.empty())
	{
		yts x=Q.top();Q.pop();
		if (x.now==T)
		{
			e-=x.g;
			if (e<0) return;
			ans++;
			continue;
		}
		if (x.g+dis[x.now]>e) continue;
		for (int p=head[x.now];p;p=next[p]) Q.push((yts){to[p],x.g+len[p]});
	}
}

int main()
{
	scanf("%d%d%lf",&n,&m,&e);
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d%lf",&x,&y,&z);
		addedge(x,y,z);add(y,x,z);
	}
	S=1,T=n;
	spfa();
	Astar();
	printf("%d\n",ans);
	return 0;
}