zoukankan      html  css  js  c++  java
  • K短路 (A*算法) [Usaco2008 Mar]牛跑步&[Sdoi2010]魔法猪学院

    A*属于搜索的一种,启发式搜索,即:每次搜索时加一个估价函数

    这个算法可以用来解决K短路问题,常用的估价函数是:已经走过的距离+期望上最短的距离

    通常和Dijkstra一起解决K短路

    BZOJ1598:牛跑步

    求前K短路

    因为A*算法我们每次用来向外拓展的是估价函数最小的点,那么,我们必定能够得到,第一个到达n的是最短路。(Dijkstra的贪心,可证)

    那么,我们思考一下,第二个到达n的就是次短路!

    由此观之:第K个到达的就是K短路

    因此,A*算法可以用来解决K短路问题

    附上代码:

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <iostream>
    #include <map>
    using namespace std;
    #define N 10005
    #define ll long long
    struct node
    {
    	int to,next,val;
    }e[N*10],E[N*10];
    int head[N],cnt,cnt1,n,m,K,vis[N],head1[N];
    int dis[N];
    void add(int x,int y,int z)
    {
    	e[cnt].to=y;
    	e[cnt].next=head[x];
    	e[cnt].val=z;
    	head[x]=cnt++;
    }
    void add1(int x,int y,int z)
    {
    	E[cnt1].to=y;
    	E[cnt1].next=head1[x];
    	E[cnt1].val=z;
    	head1[x]=cnt1++;
    }
    priority_queue<pair<int ,int > >q;
    void Dijkstra()
    {
    	memset(dis,0x3f,sizeof(dis));
    	dis[n]=0;
    	q.push(make_pair(0,n));
    	while(!q.empty())
    	{
    		int x=q.top().second;q.pop();
    		if(vis[x])continue;
    		vis[x]=1;
    		for(int i=head1[x];i!=-1;i=E[i].next)
    		{
    			int to1=E[i].to;
    			if(dis[to1]>dis[x]+E[i].val)
    			{
    				dis[to1]=dis[x]+E[i].val;
    				q.push(make_pair(-dis[to1],to1));
    			}
    		}
    	}
    }
    void Astar(int s)
    {
    	q.push(make_pair(-dis[s],s));
    	while(!q.empty())
    	{
    		int d=q.top().first;int x=q.top().second;q.pop();
    		if(x==n)
    		{
    			K--;
    			printf("%d
    ",-d);
    			if(!K)return ;
    		}
    		for(int i=head[x];i!=-1;i=e[i].next)
    		{
    			int to1=e[i].to;
    			q.push(make_pair(d+dis[x]-e[i].val-dis[to1],to1));
    		}
    	}
    }
    int main()
    {
    	memset(head1,-1,sizeof(head1));
    	memset(head,-1,sizeof(head));
    	scanf("%d%d%d",&n,&m,&K);
    	for(int i=1;i<=m;i++)
    	{
    		int x,y,z;
    		scanf("%d%d%d",&x,&y,&z);
    		add(y,x,z);
    		add1(x,y,z);
    	}
    	Dijkstra();
    	Astar(1);
    	while(K--)puts("-1");
    	return 0;
    }
    

    1975: [Sdoi2010]魔法猪学院

    这个贪心贪的很显然,为了尽可能的多,自然是选择前K短路

    那么,同样,我们用Dijkstra的贪心方法求n的前K短路

    但是这种方法实际的时间复杂度不是很对,理论上可以过很多题。这道题BZOJ可以过,但是洛谷上过不去

    附上不完美的代码:

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <iostream>
    #include <map>
    using namespace std;
    #define N 5005
    #define ll long long
    struct node
    {
    	int to,next;
    	double val;
    }e[200005],E[200005];
    int head[N],cnt,cnt1,n,m,vis[N],head1[N],ans;
    double dis[N],K;
    void add(int x,int y,double z)
    {
    	e[cnt].to=y;
    	e[cnt].next=head[x];
    	e[cnt].val=z;
    	head[x]=cnt++;
    }
    void add1(int x,int y,double z)
    {
    	E[cnt1].to=y;
    	E[cnt1].next=head1[x];
    	E[cnt1].val=z;
    	head1[x]=cnt1++;
    }
    priority_queue<pair<double ,int > >q;
    void Dijkstra()
    {
    	for(int i=0;i<N;i++)dis[i]=1e9;
    	dis[n]=0;
    	q.push(make_pair(0,n));
    	while(!q.empty())
    	{
    		int x=q.top().second;q.pop();
    		if(vis[x])continue;
    		vis[x]=1;
    		for(int i=head1[x];i!=-1;i=E[i].next)
    		{
    			int to1=E[i].to;
    			if(dis[to1]>dis[x]+E[i].val)
    			{
    				dis[to1]=dis[x]+E[i].val;
    				q.push(make_pair(-dis[to1],to1));
    			}
    		}
    	}
    }
    void Astar(int s)
    {
    	q.push(make_pair(-dis[s],s));
    	while(!q.empty())
    	{
    		double d=q.top().first;int x=q.top().second;q.pop();
    		if(x==n)
    		{
    			if(K+d<0-1e-9)return ;
    			K+=d;
    			ans++;
    		}
    		for(int i=head[x];i!=-1;i=e[i].next)
    		{
    			int to1=e[i].to;
    			q.push(make_pair(d+dis[x]-e[i].val-dis[to1],to1));
    		}
    	}
    }
    int main()
    {
    	memset(head1,-1,sizeof(head1));
    	memset(head,-1,sizeof(head));
    	scanf("%d%d%lf",&n,&m,&K);
    	for(int i=1;i<=m;i++)
    	{
    		int x,y;double z;
    		scanf("%d%d%lf",&x,&y,&z);
    		add(x,y,z);
    		add1(y,x,z);
    	}
    	Dijkstra();
    	Astar(1);
    	printf("%d
    ",ans);
    	return 0;
    }
    

    正解是用可持久化可并堆+A*算法,挖坑待填

  • 相关阅读:
    Scrapy+Scrapy-redis+Scrapyd+Gerapy 分布式爬虫框架整合
    centos7 安装软件指南
    Kafka--消费者
    Kafka--生产者
    Kafka--初识Kafka
    Kafka--Kafka简述
    NetWork--记一次Http和TLS抓包
    JVM--a == (a = b)基于栈的解释器执行过程
    Java容器--Queue
    Idea--使用Idea调试设置
  • 原文地址:https://www.cnblogs.com/Winniechen/p/9042896.html
Copyright © 2011-2022 走看看