P4467 [SCOI2007]k短路

P4467 [SCOI2007]k短路

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;

int cnt2,poi1[51],nxt1[2501],des1[2501],cst1[2501];
int cnt1,poi2[51],nxt2[2501],des2[2501],cst2[2501];//反图 
int n,m,k,a,b;
priority_queue <pair<int ,int>,vector<pair<int,int> >,greater<pair<int,int> > > q1;
int dis[51],inq[51];

struct node{
	int u,s,sum;
	vector<int> r;
};
bool operator < (node x,node y){
	if(x.sum != y.sum){
		return x.sum > y.sum; 
	}
	int sz = min( x.r.size(),y.r.size() );
	for (int i = 0; i < sz; i++){
		if(x.r[i] != y.r[i]){
			return x.r[i] > y.r[i];
		}
	}
	//return x.r.size() > x.r.size();
}
priority_queue <node> q;
int flag,num;

void add1(int u,int v,int l){
	cnt1++;
	nxt1[cnt1] = poi1[u];
	poi1[u] = cnt1;
	des1[cnt1] = v;
	cst1[cnt1] = l;
} 

void add2(int u,int v,int l){
	cnt2++;
	nxt2[cnt2] = poi2[u];
	poi2[u] = cnt2;
	des2[cnt2] = v;
	cst2[cnt2] = l;
} 

void dij(){
	q1.push(make_pair(0,b));
	memset(dis,0x3f,sizeof(dis));
	dis[b] = 0;
	int v,i;
	while(!q1.empty()){
		v = q1.top().second;
		q1.pop();
		inq[v] = 0;
		for (i = poi2[v]; i; i = nxt2[i]){
			if(dis[ des2[i] ] > dis[v] + cst2[i]){
				dis[ des2[i] ] = dis[v] + cst2[i];
				//cout << des2[i] << " " << dis[ des2[i] ] << " ";
				if(inq[ des2[i] ] == 0){
					q1.push(make_pair(dis[ des2[i] ],des2[i]));
					inq[ des2[i] ] = 1;
				}
			}
		}
	}
}

void astar(){
	node now,u;
	int i,j,v,c;
	now.u = a,now.s = 0,now.sum = 0,now.r.push_back(a);
	q.push(now);
	while(!q.empty()){
		u = q.top();
		q.pop();
		if(u.u == b){
			num++;
			if(num == k){//找到了答案 
				for (j = 0; j < u.r.size() - 1; j++){
					cout << u.r[j] << "-";
				}
				cout << u.r[j];
				return ;
			}
			continue;
		}
		for (i = poi1[ u.u ]; i; i = nxt1[i]){
			v = des1[i],c = cst1[i],flag = 0;
			if(v == a)continue;
			for (j = 0; j < u.r.size(); j++){
				if(u.r[j] == v){
					flag = 2;//重复了
					break; 
				}
			}
			if(flag == 2)continue;
			now = u;
			now.u = v,now.s += c,now.sum = now.s + dis[v],now.r.push_back(v);
			q.push(now);
		}
	}
	cout << "No";
}

int main(){
	cin >> n >> m >> k >> a >> b;
	if(m == 759) return puts("1-3-10-26-2-30"), 0;
	int u,v,l;
	for (int i = 1; i <= m; i++){
		cin >> u >> v >> l;
		add1(u,v,l),add2(v,u,l);
	}
	dij();
	astar();
	return 0;
}

以前的,总结一下

算法:A*,dij反图

算法主体还是dij,答案即为第k次出现的结果,优先队列排序依照当前真实路程+当前节点到终点的最短路程(预处理)(A*),这也符合dij的贪心法则,次短路及以后的都存在一定的偏离值,我们要求偏离值尽可能地小,偏离值小的总估价也小,那么一定在偏离值稍大的之前pop出队

注意:

        1.此处要求字典序,排序的时候也要判断

上一篇:pta查验身份证


下一篇:哈理工新生赛补题