AcWing 178 K-short circuit (second start over)

table of Contents

Topic Link 

Algorithm 1 Dijkstra violence to solve

Algorithm 2  A * algorithm


Topic Link 

https://www.acwing.com/problem/content/description/180/

The questions were very direct, is seeking short-circuit the first K

Algorithm 1

Dijkstra K short circuit can be solved first:

Dijkstra's algorithm is based on greed, review the stack optimized Dijkstra, taken from the heap for the first time dist value to the target point is the minimum, because we are just the most short-circuited before, so also with a visit[N]mark which access the array which no access, because it must be the shortest path once taken out from the heap first. If the shortest path taken out later, he has once again removed a point is taken from the heap once, then this is short sub-information recording node (excluding the shortest Shortest Path). Thus the k-th short-circuit can be solved Dijkstra.

Here you do not need to write, if (dist[to] > dist[from] + d )and which are aimed at solving the shortest set of conditions, can now directly to the side join. Simultaneously with an array of number[N]recording the number of times at each point from the stack removed, in order to determine how many times the node is removed from the stack when taken out, which corresponds to the first of several short-circuited.

But this algorithm, too violent, and more will traverse a lot of points, under normal circumstances would TLE (unless the data is particularly weak).

TLE Code

/**
 * Author : correct
 */
#include <bits/stdc++.h>
using namespace std;
#define mem(a, b) memset(a, b, sizeof a)
const int N = 1010, M = 100200;
int head[M], nex[M], to[M], ed[M], cnt;
void add(int a, int b, int c){
	++cnt;
	to[cnt] = b;
	ed[cnt] = c;
	nex[cnt] = head[a];
	head[a] = cnt;
}
int number[N];
int dist[N];
int S, T, K, n, m;
struct p{
	int x, dist;
	p(){

	}
	p(int x, int y){
		this->x = x;
		this->dist = y;
	}
	bool operator < (const p& a)const{
		return this->dist < a.dist;
	}
	bool operator > (const p& a)const{
		return this->dist > a.dist;
	}
};
void dijkstra(){
	priority_queue<p, vector<p>, greater<p> > q;
	q.push(p(S, 0));
	while (q.size()){
		p t = q.top();
		q.pop();
                number[t.x]++;// 每次出队,记录这是第几次
		if (t.x == T){
			dist[number[t.x]] = t.dist;
			if (number[T] == K)return;// 如果这是第k次,说明已经是第K短路
		}
		for (int i = head[t.x]; ~i; i = nex[i]){
			int y = to[i];
			int c = ed[i];
			if (number[y] >= K)continue;// 求k短路,其余的点的k+1,k+2等等短路用不到
			q.push(p(y, c + t.dist));
		}
	}
}
int main()
{
	ios::sync_with_stdio(0);
	mem(head, -1);
	mem(to, -1);
	cnt = 0;
	mem(number, 0);
	mem(dist, 0x3f);
	cin >> n >> m;
	while (m--){
		int a, b, c;
		cin >> a >> b >> c;
		add(a, b, c);
	}
	cin >> S >> T >> K;
	if (S == T)K++;// 题目中说每个K短路至少含一条边,对于起点和终点相同的情况
                   //显然应该去掉自身到自身为0的情况,可以通过求K+1短路间接实现
	dijkstra();
	if (dist[K] == 0x3f3f3f3f)dist[K] = -1;
	cout << dist[K];
	return 0;
}

Algorithm 2 

Above algorithm too violent, overtime is normal, need to be optimized. TLE algorithm can throw a heuristic function, so that every time he selected as a superior points to expansion. A * algorithm.

We define a function f(x)representing xthe subsequent cost estimates, assuming there is another function g(x)represents the xpoint of subsequent real cost requirements:f(x)\leq g(x)

If f(x)=g(x)we can be sorted according to estimates from small to large price, this is the case, in accordance with the order to go, you can get the most direct short circuit. Because the current estimate of the cost is the real cost of, say, you are now at the starting point s, t is the end, you know all the values from s to t of the real costs, and it is lined up order, of course, is the smallest out from s to t is the shortest. That is f(x)closer g(x) then the higher the efficiency of the algorithm, but must meetf(x)\leq g(x) . If too small, and it is such f(x)=0, then the algorithm degenerates to stack optimized Dijkstra, and still can be solved, but if too large, it will lead to this point is pressed against the bottom of the heap can not be ejected, it may generate an error. The rest is up and stack optimized Dijkstra same.

In this problem selection heuristic function may be established flanging, and then from the beginning to a value of T for each vertex as the shortest heuristic function. Because the shortest necessarily meet the above conditions, but also very close.

When finished, the establishment of the reverse side, and then optimize the stack Dijkstra shortest path to run again as the source point T, the value of dist each function as a heuristic value. Then run the A *.

AC Code

/**
 * Author : correct
 */
#include <bits/stdc++.h>
using namespace std;
#define mem(a, b) memset(a, b, sizeof a)
const int N = 1010, M = 100200;
int head[N], nex[M], to[M], ed[M], cnt, head2[N];
void add(int* h, int a, int b, int c){
	++cnt;
	to[cnt] = b;
	ed[cnt] = c;
	nex[cnt] = h[a];
	h[a] = cnt;
}
int number[N];
int dist[N];
bool vis[N];
int S, T, K, n, m;
int f(int x){
	return dist[x];
}
struct p{
	int x, dist;
	p(){}
	p(int x, int y){this->x = x;this->dist = y;}
	bool operator < (const p& a)const{return this->dist < a.dist;}
	bool operator > (const p& a)const{return this->dist > a.dist;}
};
struct p1{
	p a;
	int sum;
	p1(){}
	p1(p a, int sum){this->a = a;this->sum = sum;}
	bool operator < (const p1& t)const{return this->sum < t.sum;}
	bool operator > (const p1& t)const{return this->sum > t.sum;}
};
void dijkstra(){
	priority_queue<p, vector<p>, greater<p> > q;
	q.push(p(T, 0));
	dist[T] = 0;
	while (q.size()){
		p t = q.top();
		q.pop();
		if (vis[t.x])continue;
		vis[t.x] = 1;
		for (int i = head2[t.x]; ~i; i = nex[i]){
			int y = to[i];
			int c = ed[i];
			if (dist[y] > dist[t.x] + c){
				dist[y] = dist[t.x] + c;
				q.push(p(y, dist[y]));
			}
		}
	}
}
int A_Star(){
	priority_queue<p1, vector<p1>, greater<p1> > q;
	q.push(p1(p(S, 0), 0));
	while (q.size()){
			p1 t = q.top();
			q.pop();
			if (t.a.x == T){
				number[t.a.x]++;
				if (number[T] == K)return t.a.dist;
			}
			for (int i = head[t.a.x]; ~i; i = nex[i]){
				int y = to[i];
				int c = ed[i];
				if (number[y] >= K)continue;
				q.push(p1(p(y, c + t.a.dist), c + t.a.dist + f(y)));
			}
		}
	return -1;
}
int main()
{
	ios::sync_with_stdio(0);
	mem(head, -1);
	mem(to, -1);
	mem(head2, -1);
	mem(vis, 0);
	cnt = 0;
	mem(number, 0);
	mem(dist, 0x3f);
	cin >> n >> m;
	while (m--){
		int a, b, c;
		cin >> a >> b >> c;
		add(head, a, b, c);
		add(head2, b, a, c);
	}
	cin >> S >> T >> K;
	if (S == T)K++;// 最少包含一条边
	dijkstra();
	cout << A_Star();
	return 0;
}

A * is actually more than a stack optimized heuristic function, of course, also possible to stack as a heuristic optimization f(x)\equiv 0situation, sequence sorted according to distance from the stack side length + + heuristic function (subsequent consideration) the sum of only.

Conclusion: Why should we put it in the record silly? In fact, this question I TLE + WA afternoon because it was time to establish a counter-side of the header is not initialized, and then there is the middle point of a marked wrong, troubleshooting for a long time QAQ

Published 204 original articles · won praise 13 · views 10000 +

Guess you like

Origin blog.csdn.net/weixin_43701790/article/details/104950662