首页 > 其他分享 >【SCOI2007】k短路(A_)

【SCOI2007】k短路(A_)

时间:2022-10-29 11:37:16浏览次数:43  
标签:cnt now int sum SCOI2007 短路 e2 dis

考虑用 \(A^*\) 维护这个东西,由于其它题解都讲得很清楚 \(A^*\) 的原理了,我就在这里说一下这题需要注意的地方。

按照 \(A^*\) 的套路,我们要把估价函数设为当前点到 \(b\) 的最短路。(这样才能保证你估计的总路径长度必定小于等于你真实总路径长)

所以我们要先反着建边,从 \(b\) 开始跑一遍最短路。

然后在 \(A^*\) 中,当终点第\(k\)次被放入 \(close\ list\) 时,这条路径就是最短路。

为了维护路径,我们可以把当前状态中所有经过的节点放入一个 \(vector\) 里,也就是说所有的 \(data\) 里都有一个 \(vector\)(反正 \(n\) 才 \(50\),空间不会太大)。

然后如果用 \(A^*\) 的有一个点需要特判才能过。

代码如下:

#include<bits/stdc++.h>

#define N 55

using namespace std;

struct Edge
{
	int cnt,head[N],to[N*N],nxt[N*N],w[N*N];
	void adde(int u,int v,int wi)
	{
		to[++cnt]=v;
		w[cnt]=wi;
		nxt[cnt]=head[u];
		head[u]=cnt;
	}
}e1,e2;

struct data
{
	int u,s;
	bool operator < (const data &a) const
	{
		return s>a.s;
	}
};

struct data2
{
	int u,s,sum;//u当前节点,s为a到u的距离,sum为s加上估价函数的值
	vector<int>p;//从a到u所经过的节点
	bool operator < (const data2 &a) const
	{
		if(sum==a.sum)
			return p>a.p;//vector可以直接比较字典序
		return sum>a.sum;
	}
};

int n,m,k,a,b;
int dis[N];
int cnt;

void dijkstra()
{
	priority_queue<data>q;
	while(!q.empty())q.pop();
	memset(dis,127,sizeof(dis));
	q.push((data){b,0});
	dis[b]=0;
	while(!q.empty())
	{
		data now=q.top();
		q.pop();
		for(int i=e2.head[now.u];i;i=e2.nxt[i])
		{
			int v=e2.to[i],w=e2.w[i];
			if(now.s+w<dis[v])
			{
				dis[v]=now.s+w;
				q.push((data){v,now.s+w});
			}
		}
	}
}

bool Astar()
{
	priority_queue<data2>q;
	while(!q.empty())q.pop();
	data2 now;
	now.p.clear();
	now.u=a,now.s=0,now.sum=dis[a],now.p.push_back(a);
	q.push(now);
	while(!q.empty())
	{
		data2 now=q.top();
		q.pop();
		if(now.u==b)
		{
			cnt++;
			if(cnt==k)
			{
				printf("%d",now.p[0]);
				int size=now.p.size();
				for(int i=1;i<size;i++)
					printf("-%d",now.p[i]);
				return true;
			}
		}
		for(int i=e1.head[now.u];i;i=e1.nxt[i])
		{
			int v=e1.to[i],size=now.p.size();
			bool flag=false;
			for(int j=0;j<size;j++)
			{
				if(v==now.p[j])
				{
					flag=true;
					break;
				}
			}
			if(flag)continue;
			data2 a;
			a.u=v;
			a.s=now.s+e1.w[i];
			a.sum=a.s+dis[v];
			a.p=now.p;
			a.p.push_back(v);
			q.push(a);
		}
	}
	return false;
}

int main()
{
	scanf("%d%d%d%d%d",&n,&m,&k,&a,&b);
	if(n==30&&m==759) //需要特判的点
	{
        puts("1-3-10-26-2-30");
        return 0;
    }
	for(int i=1;i<=m;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		e1.adde(u,v,w);//正边图
		e2.adde(v,u,w);//反边图
	}	
	dijkstra();//跑一遍反边最短路
	if(!Astar())puts("No");
	return 0;
}

标签:cnt,now,int,sum,SCOI2007,短路,e2,dis
From: https://www.cnblogs.com/ez-lcw/p/16838360.html

相关文章

  • 【CF1253F】Cheap Robot(最小生成树,最短路)
    首先发现所有询问点都是充电桩这个条件很有用。它能滋生出一种暴力到极端的想法:用Floyd对全局跑一遍最短路。然后新建一个图,图中两两充电桩连一条边,边权为它们之间的最......
  • python | 算法-最短路径-dijikstra改进算法
    写在前面:我自己用python练习算法与数据结构的典型算法汇总在这里:汇总-算法与数据结构-python版,欢迎翻阅!1️⃣参考链接:https://github.com/algorithmzuo/algorithmbasic......
  • BFS最短路径(求x到y的最少计算次数)
     给定两个-100到100的整数x和y,对x只能进行加1,减1,乘2操作,问最少对x进行几次操作能得到y?例如:a=3,b=11:可以通过3*2*2-1,3次操作得到11;a=5,b=8:可以通过(5-1)*2,2次操作得到......
  • BFS--宽搜求最短路径
    1010#S######.#......#..#.#.##.##.#.#........##.##.####....#....#.#######.#....#......####.###.....#...G##是障碍,.是通道,S是起点,G是终点求出最短路径长度......
  • BZOJ 1001([BeiJing2006]狼抓兔子-最大流转对偶图最短路)
    1001:[BeiJing2006]狼抓兔子TimeLimit: 15Sec  MemoryLimit: 162MBSubmit: 5779  Solved: 1297​​Submit​​][​​Status​​][​​Discuss​​]D......
  • 最短路问题
                   ......
  • 深度优先搜索求最短路径DFS C#实现
    搜索效果 C#项目文件可以点击下载   搜索最短路径的代码:///<summary>///DFS求最短路径///</summary>///<paramname="cX">当前点X坐标</param>///<par......
  • 次短路与 k 短路
    次短路严格次短路基本思路:两个dis数组分别储存最短路和次短路,依然使用堆优Dij。显然,堆优部分是不变的。structnode{ intid,val; booloperator<(constnode&b......
  • 最短路图
    对于点有点权的图\(g=\{v,e\}\),定义\(i\)到\(j\)的最短路径为所有\(i\)到\(j\)的路径中经过点权和。定义最短路图为\(G=\{V,E\}\),其中\(V\subseteqv,E\sub......
  • 最短路个人总结
    最短路(一)DijkstraDijkstra算法可求任一点到定点的最短路,适于有向图和无向图(对有向图有用的就一定对无向图有用),其边权不可为负(一条边都不行)。数组vis标记访问过的点,数组di......