Shortest Path Problem (Luogu Training Ground and Various Summaries)

Posted by iraja on Tue, 10 Sep 2019 07:26:46 +0200

P1462 Road to Ogrema

Topic: Finding the Minimum of the Maximum Weight of the Midpoint of the Shortest Path

The minimum of the maximum value, the maximum of the minimum value, generally this kind of question will think of the dichotomy answer to solve.

So we first put all the weights in order (dichotomy needs to meet the order), then we divide the weights and run the shortest path once to confirm whether the scheme is feasible (when we take the path, the HP of the loss of edge weight should be as small as possible, so that we can reach the final point and maintain the answer.

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
#define int long long
#define ll int
const int maxn = 1e6+5;
struct Edge{
    int u,v,nxt,c;
}edge[maxn<<1];
struct Node{
    int u,dis;
    bool operator <(const Node &h)const{
        return dis > h.dis;
    }
};
int head[maxn],tot;
inline void init(){
    memset(head,-1,sizeof(head));
    tot = 0;
}
inline void addedge(int u,int v,int c){
    ++tot;
    edge[tot] = {u,v,head[u],c};
    head[u] = tot;
}
int f[maxn],ff[maxn];
int dis[maxn];
bool vis[maxn];
bool dijiastra(int u,int v,int fm,int hp){
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[u]  = 0;
    if(fm < ff[u])   return false;


    priority_queue<Node> pq;    pq.push(Node{u,0});
    while(!pq.empty()){
        Node x = pq.top();  pq.pop();
        if(vis[x.u])    continue;
        vis[x.u] = true;
        for(int i = head[x.u]; ~i; i = edge[i].nxt){
            Edge &e = edge[i];
            if(ff[e.v] > fm) continue;
            if(dis[e.v] > dis[x.u] + e.c){
                dis[e.v] = dis[x.u] + e.c;
                pq.push(Node{e.v,dis[e.v]});
            }
        }
    }
    return dis[v] <= hp;
}
signed main()
{
    init();
    int n,m,b;  cin >> n >> m >> b;
    for(int i = 1; i <= n; ++i){
        cin >> f[i];    ff[i] = f[i];
    }
    sort(f+1,f+n+1);


    for(int i = 0; i < m; ++i){
        int u,v,c;  cin >> u >> v >> c;
        addedge(u,v,c);
        addedge(v,u,c);
    }
    if(!dijiastra(1,n,f[n],b)){
        cout << "AFK" << endl;
        return 0;
    }
    int l = 1,r = n;
    int ans = 1e9;
    while(l <= r){
        int mid = l + r >> 1;
        if(dijiastra(1,n,f[mid],b)){
            ans = f[mid];
            r = mid-1;;
        }
        else l = mid+1;
    }
    cout << ans << endl;
    return 0;
}

Topic:
There is a special tram network in a magical town. It consists of some intersections and tracks. Each intersection connects several tracks, and each track leads to one intersection (it is not excluded that some sightseeing tracks turn around and return to the intersection). At each intersection, there is a switch to determine the outgoing track. Each switch has a default state. After each tram reaches the intersection, it can only go out from the track indicated by the switch. If the tram driver wants to take another track, he must get off and switch the state of the switch.
In order to get to the destination, tram drivers have to get off frequently to switch switches, so they want to ask you to write a program to calculate that a car from intersection A to intersection B needs to switch at least a few times.

Convert to the shortest path to consider the problem. If you need to switch the switch down, then u - > V is equal to the edge weight given to 1, and vice versa, the edge weight is 0. Running the shortest path once can get the answer.

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
const int maxn = 1e5+5;
struct Edge{
    int u,v,nxt;
}edge[maxn];
struct Node{
    int u,dis;
    bool operator <(const Node &h)const{
        return dis > h.dis;
    }
};
int head[maxn],tot;
inline void init(){
    memset(head,-1,sizeof(head));
    tot = 0;
}
inline void addedge(int u,int v){
    ++tot;
    edge[tot] = {u,v,head[u]};
    head[u] = tot;
}
int state[maxn];    // Switching state of each point
int dis[maxn];  bool vis[maxn];
const int inf = 0x3f3f3f3f;
void dijiastra(int s,int t){
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[s] = 0;
    priority_queue<Node> pq;    pq.push(Node{s,0});
    while(!pq.empty()){
        Node x = pq.top();  pq.pop();
        if(vis[x.u])    continue;   vis[x.u] = true;
        for(int i = head[x.u]; ~i; i = edge[i].nxt){
            Edge &e = edge[i];
            int tag = (state[x.u]==e.v? 0 : 1);
            if(dis[e.v] > dis[x.u] + tag){
                dis[e.v] = dis[x.u] + tag;
                pq.push(Node{e.v,dis[e.v]});
            }
        }
    }
    if(dis[t]==inf) cout << -1 << endl;
    else cout << dis[t] << endl;
}
int main()
{
    init();
    int n,a,b;  cin >> n >> a >> b;
    for(int i = 1; i <= n; ++i){
        int k;  cin >> k;
        for(int j = 0; j < k; ++j){
            int x;  cin >> x;
            if(!j)  state[i] = x;
            addedge(i,x);
        }
    }
    dijiastra(a,b);
    return 0;
}

Shortest Path Floyed

(Looking at a wave of other people's questions) I have a new understanding of floyed. I thought that because of the complexity of O (n3) O (n3) O (n3) O (n3), the application area of Floyed has been very narrow, but in fact, my understanding of Floyed is not enough.
The main idea of this algorithm is to find the shortest path between two points through other points. Because we know that there are many paths between the two points. If we change paths to shorten the distance, we will update the shortest distance. And its most essential idea is to use other points to transfer, so as to achieve the goal of finding the shortest path.

So, how to transfer? The shortest path can be updated by one point as a transit point between two points, or by multiple points.

Combining code:

for(k=1;k<=n;k++)

    for(i=1;i<=n;i++)

        for(j=1;j<=n;j++)

            if(e[i][j]>e[i][k]+e[k][j])

                 e[i][j]=e[i][k]+e[k][j];

// Core code, only five lines
The basic idea of this code is that at first, only vertex 1 is allowed to transit, and then vertex 1 and vertex 2 are allowed to transit... The shortest path between any two points can be obtained by transferring through all vertices of No. 1-n. In a word, the shortest distance from vertex i to vertex j only passes through the first k point.

Post-disaster reconstruction of P1119

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 2e2+5;
int day[maxn];
int dp[205][205];
inline void floyed(int k,int n){
	for(int i = 0; i < n; ++i){
		for(int j = 0; j < n; ++j){
			if(dp[i][j] > dp[i][k] + dp[j][k]){
				dp[i][j] = dp[j][i] = dp[i][k] + dp[j][k];
			}
		}
	}
}
const int inf = 0x3f3f3f3f;
int main()
{
	memset(dp,0x3f,sizeof(dp));
	int n,m;	cin >> n >> m;
	for(int i = 0; i < n; ++i)	cin >> day[i];
	for(int i = 0; i < m; ++i){
		int u,v,w;	cin >> u >> v >> w;
		dp[u][v] = w;	dp[v][u] = w;
	}
	for(int i = 0; i < n; ++i)
		dp[i][i] = 0;
	int now = 0;
	int Q;	cin >> Q;
	for(int i = 0; i < Q; ++i){
		int x,y,t;	cin >> x >> y >> t;
		while(day[now] <= t && now < n){
			floyed(now,n);	++now;
		}
		if(day[x] > t || day[y] > t){
			cout << -1 << endl;
		}else{
			if(dp[x][y]==inf){
				cout << -1 << endl;
			}
			else cout << dp[x][y] << endl;
		}

	}
	return 0;
}

Question B of the 2019 Nanchang Network Invitation Competition (using the method of virtual node connection)

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 1e6+1e5;
int v,e,ss,k,c;
struct Edge{
	int u,v,nxt,w;
}edge[maxn];
struct Node{
	int u,dis;
	bool operator < (const Node &h)const{
		return dis > h.dis;
	}
};
int tot,head[1005];
inline void addedge(int u,int v,int w){
	++tot;
	edge[tot] = {u,v,head[u],w};
	head[u] = tot;
}
int dis[1005];
bool vis[1005];
int heroMax,xfdd,xfdw[1005],tot2;

void dijiastra(int s,int n){
	memset(dis,0x3f,sizeof(dis));	memset(vis,0,sizeof(vis));
	dis[s] = 0;

	priority_queue<Node> pq;	pq.push(Node{s,0});
	while(!pq.empty()){
		Node x = pq.top();	pq.pop();
		if(vis[x.u])	continue;
		vis[x.u] = true;
		for(int i = head[x.u]; ~i; i = edge[i].nxt){
			Edge & e = edge[i];
			if(!vis[e.v] && dis[e.v] > x.dis + e.w){
				dis[e.v] = x.dis + e.w;
				pq.push(Node{e.v,dis[e.v]});
			}
		}
	}

}
inline void init(){
	memset(head,-1,sizeof(head));
	heroMax = 0;
	xfdd = 0;
	tot = 0;
}
int main()
{
	int T;	scanf("%d",&T);
	while(T--){
		init();
		scanf("%d%d%d%d%d",&v,&e,&ss,&k,&c);
		int nn = v+1;


		for(int i = 0; i < k; ++i){
			int x;	scanf("%d",&x);
			xfdw[i] = x;
			addedge(nn,x,0);
		}

		for(int i = 0; i < e; ++i){
			int u,v,w;	scanf("%d%d%d",&u,&v,&w);
			addedge(u,v,w);
			addedge(v,u,w);
		}

		dijiastra(nn,v);
		for(int j = 1; j <= v; ++j)	xfdd = max(xfdd,dis[j]);


		dijiastra(ss,v);
		for(int i = 1; i <= v; ++i){
			heroMax = max(heroMax,dis[i]);
		}


		if(heroMax <= xfdd*c){
			printf("%d\n",heroMax);
		}
		else printf("%d\n",xfdd);

	}
	return 0;
}

Topics: network