Shandong University of science and technology 2021 national ladder competition pre competition individual topic intensive competition -- 4 (shortest path) supplementary questions

Posted by Eric! on Fri, 04 Mar 2022 20:14:38 +0100

Save 007 (upgraded)

In the old movie "Live and Let Die", 007 is caught by a drug dealer on an island in the center of a crocodile pool. He uses an extremely bold way to escape - stepping directly on the brain bags of a series of crocodiles in the pool and jumping ashore! (it is said that the stuntman was bitten by the last crocodile. Fortunately, he escaped with extra thick boots.)

The crocodile pool is a square with a length and width of 100m, the center coordinate is (0,0), and the northeast corner coordinate is (50,50). The pond core island is a circle with a diameter of 15 meters with (0,0) as the center. Given the coordinates of the crocodiles distributed in the pool and the maximum distance 007 can jump at one time, you need to show him the shortest escape path - the so-called "shortest" means that 007 has the least steps to jump.

Input format:
First, the first line gives two positive integers: the number of crocodiles N (≤ 100) and the maximum distance D that 007 can jump at one time. Then N lines, each giving the (x,y) coordinates of a crocodile. Note: there will not be two crocodiles at the same point.

Output format:
If 007 is likely to escape, first output the minimum number of steps 007 needs to jump in the first line, and then from the second line, each line gives the coordinates (x,y) of the crocodile to jump in each step from the pond core island to the shore. If it is impossible to escape, output 0 on the first line as the number of jump steps. If the shortest path is not unique, the nearest solution of the first hop is output. The problem ensures that such a solution is unique.

Input example 1:
17 15
10 -21
10 21
-40 10
30 -50
20 40
35 10
0 -10
-25 22
40 -40
-30 30
-10 22
0 11
25 21
25 10
10 10
10 35
-30 10
Output example 1:
4
0 11
10 21
10 35
Input example 2:
4 13
-12 12
12 12
-12 -12
12 -12
Output example 2:
0

Idea:
I Connect the points that can jump with each other through an array to form a picture. In the picture, you should record who jumps to whom and the distance.
II For each point that can jump, it should be sorted by distance, because the title says that if there are steps with the same number, it will be output with the smaller distance of the first jump point.
III The operation of bfs starts with the first point (origin), and whether the retrieval can escape directly.
1. If you can't escape directly, retrieve this point, which points you can jump to, put them in the queue, and mark that they have been skipped. The path [] array is used to record who jumps to whom, that is, the path. For example, if path[2]=1, it is defined as jumping from 1 to 2, that is, the subscript is the starting point of the jump and the value is the end point of the jump.
2. If a point is retrieved and can escape directly, start outputting steps and paths. For the number of steps, you can keep + 1 when saving the path, and the path needs to open a new ans [] array to save the point number. You should save it from the outside to the inside. This is because when the two points connected with path [] were originally connected, the value of the array is the previous point, so saving it from the outside to the inside is convenient for traversal. After traversing a point each time, update the path [] array, You can know who the number of its last point is. What is stored in the ANS [] array is the subscript of the point. It can be output backwards at the last output.

The following is to connect the points that can jump over to form a picture

for(int i=1;i<n;i++){
        for(int j=i+1;j<=n;j++){ //Here, the points that can be jumped are connected to form a graph. If you can jump, it shows that there are edges
            double di=dis(i,j);
            if(i==1){     //Initial point special judgment
                if(di<=d+7.5){ 
                p[i].push_back(make_pair(j,di)); //Here, i-j is stored in pair, and the distance is di, indicating that the two points can be connected
                p[j].push_back(make_pair(i,di));
                }
            }
            else{
                if(di<=d){ //As long as you can jump over the other points, you can connect them,
                    p[i].push_back(make_pair(j,di));
                    p[j].push_back(make_pair(i,di));
                }
            }
        }
    }

This is sorted by distance

for(int i=1;i<=n;i++){ //Sort according to the length of the edges
        sort(p[i].begin(),p[i].end(),cmp);
    }

Here is the point retrieval process, including 2 small steps. 1. If a certain point is retrieved, you can escape; 2. If it is not retrieved, you can retrieve the next point and use the queue to number the point.

void bfs(){
    vis[1]=1; //The first point has passed, so mark it
    queue<int> q;
    q.push(1);  //Put the origin in
    while(!q.empty()){
        int k=q.front();
        q.pop();
        if(check(k)){ //If a point can jump out of the island directly, it starts to output
            int ans[N],cnt=0;  //ans stores the number of jump points, and cnt is the number of jumps
            while(path[k]!=0){ //From outside to inside, store the point. When path[k] is 0, it indicates that it is the origin
                ans[cnt++]=k;  //Put point k into ans
                k=path[k];   //Update K to the previous point of point K, because path[k] stores who jumps to K, the value is the starting point of jump, and the subscript is the end point of jump
            }
            printf("%d\n",cnt+1); //Because cnt didn't record jumping off the island from the last crocodile point, it needs + 1
            for(int i=cnt-1;i>=0;i--) printf("%.0lf %.0lf\n",x[ans[i]],y[ans[i]]); //Here, because it is stored backwards when saving, it should be output backwards
            return ;
        }
        for(int i=0;i<p[k].size();i++){  
            int now=p[k][i].first; //Refers to the number of points,
            if(!vis[now]){  //If you haven't gone, go
                vis[now]=1;
                path[now]=k; //The path array means that you can jump from k to now, that is, the number of the previous point of the node
                q.push(now); //Put this point in the queue
            }
        }
    }
    printf("0"); //The last way was not retrieved, that is 0
}

Here is the complete code

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
double x[N],y[N],vis[N],d; //They are the X and Y coordinates, whether they have walked through the state, and the jumping distance
int n,path[N]; //The record side is who can jump to who
vector<pair<double,double>>p[N];  //Sort by distance
bool cmp(pair<double,double> a,pair<double,double> b){
    return a.second<b.second;
}
double dis(int a,int b){  //Find the distance between two points
    return sqrt(pow(x[a]-x[b],2)+pow(y[a]-y[b],2));
}
bool check(int a){  //Judge whether you can escape
    if(50-abs(x[a])<=d||50-abs(y[a])<=d) return 1;
    return 0;
}
void bfs(){
    vis[1]=1; 
    queue<int> q;
    q.push(1);  
    while(!q.empty()){
        int k=q.front();
        q.pop();
        if(check(k)){ 
            int ans[N],cnt=0;  
            while(path[k]!=0){ 
                ans[cnt++]=k;  
                k=path[k];   
            }
            printf("%d\n",cnt+1); 
            for(int i=cnt-1;i>=0;i--) printf("%.0lf %.0lf\n",x[ans[i]],y[ans[i]]); 
            return ;
        }
        for(int i=0;i<p[k].size();i++){  
            int now=p[k][i].first; 
            if(!vis[now]){  
                vis[now]=1;
                path[now]=k; 
                q.push(now); 
            }
        }
    }
    printf("0"); 
}
int main(){
    scanf("%d%lf",&n,&d);
    ++n;
    x[1]=0,y[1]=0;
    for(int i=2;i<=n;i++){
        scanf("%lf%lf",&x[i],&y[i]); 
    }
    for(int i=1;i<n;i++){
        for(int j=i+1;j<=n;j++){ 
            double di=dis(i,j);
            if(i==1){  
                if(di<=d+7.5){ 
                p[i].push_back(make_pair(j,di)); 
                p[j].push_back(make_pair(i,di));
                }
            }
            else{
                if(di<=d){ 
                    p[i].push_back(make_pair(j,di));
                    p[j].push_back(make_pair(i,di));
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        sort(p[i].begin(),p[i].end(),cmp);
    }
    bfs();
    return 0;
}

Harry Potter's Exam

In Professor McGonagall's class of Transfiguration, Harry Potter is learning how to transform one object into another by some spells. He has learnt that, to turn a cat into a mouse one can say docamo! To reverse the effect, simply say decamo! Formally speaking, the transfiguration spell to transform between object A and object B is said to be S if there are two spells, doS and deS, to turn A into B and vice versa, respectively.

In some cases, short-cut spells are defined to make transfiguration easier. For example, suppose that the spell to transform a cat to a mouse is docamo, and that to transform a mouse into a fatmouse is dofamo, then to turn a cat into a fatmouse one may say docamodofamo! Or if a shot-cut spell is defined to be cafam, one may get the same effect by saying docafam!

Time is passing by quickly and the Final Exam is coming. By the end of the transfiguration exam, students will be requested to show Professor McGonagall several objects transformed from the initial objects they bring to the classroom. Each of them is allowed to bring 1 object only.

Now Harry is coming to you for help: he needs a program to select the object he must take to the exam, so that the maximum length of any spell he has to say will be minimized. For example, if cat, mouse, and fatmouse are the only three objects involved in the exam, then mouse is the one that Harry should take, since it will take a 6-letter spell to turn a mouse into either a cat or a fatmouse. Cat is not a good choice since it will take at least a 7-letter spell to turn it into a fatmouse. And for the same reason Harry must not take a fatmouse.

Input Specification:
Each input file contains one test case. For each case, the first line contains two positive integers N (≤100) and M, which are the total number of objects involved in the exam and the number of spells to be tested, respectively. For the sake of simplicity, the objects are numbered from 1 to N. Then M lines follow, each contains 3 integers, separated by a space: the numbers of two objects, and the length of the spell to transform between them.

Output Specification:
For each test case, print in one line the number of the object which Harry must take to the exam, and the maximum length of the spell he may have to say. The numbers must be separated by a space.

If it is impossible to complete all the transfigurations by taking one object only, simply output 0. If the solution is not unique, output the one with the smallest number.

Sample Input:
6 11
3 4 70
1 2 1
5 4 50
2 6 50
5 6 60
1 3 70
4 6 60
3 6 80
5 1 100
2 4 60
5 2 80
Sample Output:
4 70
Meaning: let you find a point. The maximum value of the shortest path from this point to other points is smaller than the maximum value of the shortest path from other points. Ask you which point this point is, and output the maximum value of the shortest path from this point to other stores.
Idea: directly floyd, find the maximum value of the shortest path for each point, and update the maximum value of the point and the shortest path when it is smaller.

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
const int N=1e2+10;
int n,m;
int p[N][N];
void floyd(){
     for(int k=1;k<=n;k++){
         for(int i=1;i<=n;i++){
             for(int j=1;j<=n;j++){
                 if(p[i][j]>p[i][k]+p[k][j]){
                     p[i][j]=p[i][k]+p[k][j];               
                 }
             }
         }
     }
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(p,inf,sizeof(p));
    for(int i=0;i<m;i++){
        int u,v,dis;
        scanf("%d%d%d",&u,&v,&dis);
        p[u][v]=p[v][u]=dis; //Undirected graph
    } 
    floyd(); //Multi source shortest path
    int minn=inf,now=-1; //Respectively used to find the maximum value of the shortest circuit and the number of points
    for(int i=1;i<=n;i++){
         int maxx=0,flag=1;
         for(int j=1;j<=n;j++){
             if(i==j){  //I think I don't think about it
                 continue;
             }
            if(p[i][j]==inf){ //If not, it means that this point cannot reach all other points
                flag=0;
                 break;
             }
             if(p[i][j]>maxx){ //Update the maximum value of the shortest circuit
                 maxx=p[i][j];
             }
         }
         if(flag==0) continue;
         else{
             if(maxx!=0&&maxx<minn){ //If a smaller maximum value of the shortest path is found, it is updated
                 minn=maxx;
                 now=i;
             }
         }
    }
    if(minn==inf) printf("0\n");
    else{
        printf("%d %d\n",now,minn);
    }
    return 0;
}

Inter city emergency rescue

As the head of a city's emergency rescue team, you have a special national map. The map shows multiple scattered cities and some fast roads connecting cities. The number of rescue teams in each city and the length of each expressway connecting the two cities are marked on the map. When other cities have emergency calls for you, your task is to lead your rescue team to rush to the place of the accident as soon as possible, and at the same time, call as many rescue teams as possible along the way.

Input format:
Input the first line to give four positive integers N, m, s and D, where N (2 ≤ N ≤ 500) is the number of cities. Incidentally, suppose that the number of cities is 0 ~ (N − 1); M is the number of expressways; S is the city number of the place of departure; D is the city number of the destination.

The second line gives N positive integers, where the ith number is the number of rescue teams in the ith City, separated by spaces. In the following M lines, each line gives the information of an expressway, namely: the length of city 1, city 2 and expressway, separated by spaces, and the numbers are integers and no more than 500. The input ensures that the rescue is feasible and the optimal solution is unique.

Output format:
The first line outputs the number of shortest paths and the maximum number of rescue teams that can be convened. The second line outputs the city number passed in the path from S to D. Numbers are separated by spaces, and there must be no extra spaces at the end of the output.

Input sample:
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2
Output example:
2 60
0 1 3
Idea: use dijestra to find the shortest path. Whenever a shortest path is found, it is necessary to follow a new distance, update the number of shortest paths and the number of rescue teams convened on the way.
Use num [] array to record the original number of rescue teams at each point
Use the p [] array to record the number of rescue teams called on the way.
The last point recorded in the path [] array is the point, that is, who has reached the point.
Record the number of shortest paths with q [] array.
Whenever the shortest path is found, the distance is updated to the shorter one.
The number of shortest paths is updated to the number of shortest paths of the previous point. (for example) for example, from a to b, because it comes to point b through the shortest path from point a, it needs to pass through a to get to point b (in the case of the shortest distance, it is not called the number of shortest paths in other distances), so there are several paths in a and several paths in b.
The number of rescue teams you call becomes the number of people you call before passing through point b + the number of local people at point b
When the shortest path is the same, the number of shortest paths in these two cases should be added up, because these two are the shortest paths. At this time, it is necessary to make a decision on the number of rescue teams to be convened. It must be the one that can worry about more rescue teams.
During each update, the last point of the point shall be recorded to facilitate the final output.

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
#define inf 0x3f3f3f3f
int n,m,s,d;
int g[N][N],num[N];//City map, number of rescue teams at this point
int p[N],path[N],q[N]; //The number of rescue teams summoned at the point, the city number experienced before reaching the city, and the number of shortest paths to the point
int vis[N]; //Have you walked
void dijkstra(){
    vis[s]=1; //The starting point is marked as 1
    q[s]=1; 
    for(int i=0;i<n;i++){
        int min=inf,k=-1;
        for(int j=0;j<n;j++){  //Here is the shortest circuit
            if(vis[j]==0&&g[s][j]<min){
                 min=g[s][j]; //Note the shortest path
                 k=j;     //Write down the number
            }
        }
        if(k==-1) break; 
        else vis[k]=1; //Go to this point and mark it as 1
        for(int j=0;j<n;j++){ 
            if(vis[j]==0&&g[s][j]>g[s][k]+g[k][j]){
                g[s][j]=g[s][k]+g[k][j]; //Update the shortest distance from the starting point to j
                q[j]=q[k];    //Because it is from to k to j, there are several shortest paths to k, so there are several paths to j, because to get to j, we have to go through k
                p[j]=p[k]+num[j]; //The number of rescue teams summoned at point j is the number summoned at point k + the number of local rescue teams
                path[j]=k; //path stores the number that can be from point k to point j, that is, the previous point of point j
            }
            else if(vis[j]==0&&g[s][j]==g[s][k]+g[k][j]){ //When the shortest path is the same
                q[j]=q[j]+q[k]; //The shortest path to point j needs to be updated, because there are two ways to point j at this time, and the shortest paths are the same, so add up their shortest paths
                if(p[j]<p[k]+num[j]){ //When the shortest path is the same, the number of rescue teams should be compared. The one with more updates
                    path[j]=k; 
                    p[j]=p[k]+num[j];
                }
            }
        }
    }
}
int main(){
    scanf("%d%d%d%d",&n,&m,&s,&d);//Number of cities, sides, departure and destination
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(i!=j){
               g[i][j]=inf;
            }
        }
    }
    for(int i=0;i<n;i++){
        scanf("%d",&num[i]); 
        p[i]=num[i];  
        q[i]=1; //The number of shortest paths to each point is first recorded as 1
    }
    for(int i=0;i<m;i++){
        int u,v,dis;
        scanf("%d%d%d",&u,&v,&dis);
        g[u][v]=g[v][u]=dis;
    }
    dijkstra();
    printf("%d %d\n",q[d],p[d]+num[s]); //Number of shortest paths, number of rescue teams at the origin + number of rescue teams convened on the way
    int road[N]; //To save the path
    int cnt=0,t=d;
    while(path[t]!=0){  //path saves what is the last point to jump to this point, so it should be saved from the back to the front
        road[cnt++]=path[t]; 
        t=path[t];
    }
    printf("%d",s);
    for(int i=cnt-1;i>=0;i--){
        printf(" %d",road[i]);
    }
    printf(" %d\n",d);
    return 0;
}

To be continued
If you have any suggestions or criticisms and additions, please leave a message and point it out. Thank you very much

Topics: Graph Theory pta dijkstra