BFS最短路径还原+字典序UVA 1599 Ideal Path 和 UPC 4431香港记者

Posted biu~跃哥冲冲冲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BFS最短路径还原+字典序UVA 1599 Ideal Path 和 UPC 4431香港记者相关的知识,希望对你有一定的参考价值。

UVA 1599 Ideal Path

评测传送门1
评测传送门2


题目大意:@Sparky_14145提供的翻译很清楚,不再赘述。

解题思路:
源点: 1 1 1 ,汇点: n n n
先逆向求一遍单汇最短路,然后再从源点正向 B F S BFS BFS求最小字典序的路径。
在正向 B F S BFS BFS 的时候,要将当前最小的可能是最优路径上的点全部加进队列进行扩展,即满足 d i s t [ j ] + w [ i ] = d i s t [ u ] dist[j] + w[i] = dist[u] dist[j]+w[i]=dist[u]的那些结点 j j j。在此题中所有的边权都是 1 1 1,所以 w [ i ] = 1 w[i]=1 w[i]=1.

AcCoding:

#pragma G++ optimize(2)
#pragma GCC optimize(2)
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 100010, M = 400010;
int h[N], e[M], ne[M], w[M], idx;
int dist[N],res[M];
bool vis[N];
void add(int a, int b, int c) 
	e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;

void rebfs(int root) 
	memset(dist, 0x3f, sizeof dist);
	memset(vis, false, sizeof vis);
	dist[root] = 0;
	queue<int> q;
	q.push(root);
	while (q.size()) 
		int u = q.front(); q.pop();
		vis[u] = true;
		for (int i = h[u];i != -1;i = ne[i]) 
			int j = e[i];
			if (dist[j] > dist[u] + 1) 
				dist[j] = dist[u] + 1;
				q.push(j);
			
		
	

void bfs(int root,int end) 
	memset(vis, false, sizeof vis);
	memset(res, 0x3f, sizeof res);
	queue<int> q;
	q.push(root);
	vis[root] = true;
	while (q.size()) 
		int u = q.front();q.pop();
		if (u == end) break;
		int min1 = 0x3f3f3f3f;
		for (int i = h[u];i != -1;i = ne[i]) 
			int j = e[i];
			if (dist[u] == dist[j] + 1 && w[i] < min1) min1 = w[i];
		
		if (min1 != 0x3f3f3f3f) 
			for (int i = h[u];i != -1;i = ne[i]) 
				int j = e[i];
				if (!vis[j] && dist[u] == dist[j] + 1 && w[i] == min1) 
					q.push(j);
					vis[j] = true;
				
			
		
		int idx = dist[1] - dist[u];
		res[idx] = min(res[idx], min1);
	

int main() 
	int n, m; 
	while (scanf("%d%d", &n, &m) != EOF) 
		idx = 0;
		memset(h, -1, sizeof h);
		for (int i = 1;i <= m;i++) 
			int a, b, c; scanf("%d%d%d", &a, &b, &c);
			if (a == b) continue;
			add(a, b, c), add(b, a, c);
		
		int start = 1, end = n;
		rebfs(end);
		printf("%d\\n", dist[start]);
		bfs(start,end);
		for (int i = 0;i < dist[start];i++) 
			printf("%d", res[i]);
			if (i < dist[start] - 1) printf(" ");
		
		puts("");
	

	return 0;

UPC 4431 香港记者

评测传送门


题目大意:
与上面那个题类似,这个题是在最短路的基础之上同时要满足路径上结点的点权构成序列的字典序最小。

解题思路:
这个题强调是有向图,因此需要建两次图,一次正向图,一次反向图。反向图的作用也是求单汇最短路。在正向图上跑 B F S BFS BFS 寻找最优路径,扩展的时候,找到当前遍历到的可能的最小点权的的结点。与上一个题的操作操作类似,代码我也是直接拿上一个代码稍微更改了一点。特别的,起点和终点的点权一定在路径中。

ACoding:

#pragma G++ optimize(2)
#pragma GCC optimize(2)
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 200010, M = 800010;
int h[N], e[M], ne[M], w[M], idx;
ll dist[N];
int val[N];
bool vis[N];
vector<int> res;
void add(int a, int b, int c) 
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;

void rebfs(int root) 
    memset(dist, -1, sizeof dist);
    dist[root] = 0;
    queue<int> q;
    q.push(root);
    while (q.size()) 
        int u = q.front(); q.pop();
        vis[u] = true;
        for (int i = h[u];i != -1;i = ne[i]) 
            int j = e[i];
            if (dist[j] == -1 || dist[j] > dist[u] + w[i]) 
                dist[j] = dist[u] + w[i];
                q.push(j);
            
        
    

void bfs(int root,int end) 
    memset(vis, false, sizeof vis);
    queue<int> q;
    q.push(root);
    vis[root] = true;
    while (q.size()) 
        int u = q.front();q.pop();
        if (u == end) break;
        int min1 = 0x3f3f3f3f;
        for (int i = h[u];i != -1;i = ne[i]) 
            int j = e[i];
            if (dist[u] == dist[j] + w[i] && val[j] < min1) min1 = val[j];
        
        if (min1 != 0x3f3f3f3f) 
            for (int i = h[u];i != -1;i = ne[i]) 
                int j = e[i];
                if (!vis[j] && dist[u] == dist[j] + w[i] && val[j] == min1) 
                    q.push(j);
                    vis[j] = true;
                
            
            res.push_back(min1);
        
    

struct node 
    int a, b, c;
edge[M];
int main() 
    int n, m; 
    scanf("%d%d", &n, &m);
    for (int i = 1;i <= n;i++) scanf("%d", &val[i]);
    memset(h, -1, sizeof h);
    for (int i = 1;i <= m;i++) 
        int a, b, c; scanf("%d%d%d", &a, &b, &c);
        add(b, a, c);
        edge[i] =  a,b,c ;
    
    int start = 1, end = n;
    rebfs(end);
    printf("%lld\\n", dist[start]);
    memset(h, -1, sizeof h);
    idx = 0;
    for (int i = 1;i <= m;i++) add(edge[i].a, edge[i].b, edge[i].c);
    bfs(start,end);
    cout << val[1] << " ";
    for (int i = 0;i < res.size();i++) 
        printf("%d", res[i]);
        if (i < res.size() - 1) printf(" ");
    
    return 0;

以上是关于BFS最短路径还原+字典序UVA 1599 Ideal Path 和 UPC 4431香港记者的主要内容,如果未能解决你的问题,请参考以下文章

UVa 1599 理想路径(反向BFS 求最短路径 )

UVA 1599 Ideal Path(双向bfs+字典序+非简单图的最短路+队列判重)

每日一题 UVA - 1599 Ideal Path 字典序最短路

Uva 1599 最佳路径

例题 6-20 UVA - 1599Ideal Path

UVA1599带权图的最短路径以及边的保存方式