road repair plan
- describe
-
General Nan led many troops, and they were stationed in N different cities. These cities were numbered from 1 to N. Due to the inconvenience of transportation, General Nan planned to build roads.
It is now known which cities can build roads, and if so, how much it will cost.
Now, the strategist has found a way to build a road that can connect all the cities with the least cost.
However, General Nan said that the pattern formed by this road construction plan is very unlucky, and I want Xiaogong to calculate whether there is another scheme with the same cost as the previous one. Now you can help Xiaogong write a program to calculate it. .
- enter
-
Input an integer T (1<T<20) in the first line, indicating the number of test data groups The first line of
each test data group is two integers V, E, (3<V<500,10<E<200000) respectively represent the number of cities and the number of roads between cities. The data ensures that all cities are connected by road.
Subsequent E lines, each line has three numbers ABL, indicating that the road construction cost between city A and city B is L. - output
- Output Yes or No for each set of test data (if there are more than two minimum cost schemes, output Yes, if there is only one minimum cost scheme, output No)
- sample input
-
2 3 3 1 2 1 2 3 2 3 1 3 4 4 1 2 2 2 3 2 3 4 2 4 1 2
- Sample output
-
No
Yes
-
-
There are generally two ways to find the sub-minimum spanning tree for topic analysis:
-
a. Use Kruskal to generate a minimum spanning tree first and save the subscripts of the edges on each tree, then traverse the edges on these trees, and then delete the edges on each tree --> rebuild the tree- ->Update the minimum weight value-->Recovery process, every time you delete an edge of the tree, the original tree is destroyed, the rebuilt tree must not be the original tree, and the minimum weight of the rebuilt tree is the next smallest. , note that if the bridge is deleted every time the edge is deleted, which will lead to the disconnection of the graph, so in Kruskal, it is necessary to use and check the number of connected components in the statistical graph. If the entire graph is not connected, return to infinity , so that this update of the weights must fail.
-
Complexity O (n-1*complexity of Kruskal after optimization)
-
-
#include<iostream>//Import input and output stream header files #include<algorithm>//Import header file using namespace std;//Import standard namespace typedef struct edge//The structure that defines the edge { int v,w,d;//Define the two endpoints of a side and its side length bool is_delete;//Define whether to delete the flag } Edge; #define MAXN 200007//Define the maximum side length #define MAXNUM 0x3f3f3f3f//Define infinite value Edge bian[MAXN];//Create an array of edges int pre[MAXN];//Define the array of parent nodes of the collection int n,e;//Define the number of edges and the number of points int MST_id[MAXN];//Define the subscript of the tree to save the array int mid_i;//The subscript of the spanning tree array int cnt;//Define the number of components in the graph bool cmp(Edge a,Edge b) { return a.d<b.d; } int Find(int x)//compression path { int temp,p=x; while(x!=pre[x]) x=pre[x];//First find the root node of the set to which x belongs while(p!=x)//Update all root nodes on the path compressed { temp=pre[p];//Path traversal from x to root node pre[p]=x; p=temp; } return x;//Return the root node of the set } int kruskal(int p)//Enter Kruskal algorithm { int sum=0;//Define the minimum spanning tree weight and sum for(int i=0;i<e;i++)//traverse each edge { int p1=Find(bian[i].v); int p2=Find(bian[i].w); if(bian[i].is_delete==false&&p1!=p2)//If this edge is not marked for deletion, and the two point sets do not have a parent node { cnt--;//The number of sets minus one pre[p1]=pre[p2];//The parent node changes sum+=bian[i].d;//Weights and the weights of this edge if(p==1)//If it is the first generation { MST_id[mid_i++]=i;//Record the id of the edge of the minimum spanning tree } if(cnt==1) break; } } if(cnt==1)//If the last full graph is connected, return the weight and return sum; else//Otherwise return infinity return MAXN; } void init()//Initialize the parent node and the number of sets cnt { for(int i=0;i<=n;i++) pre[i]=i; cnt=n; } intmain() { ios::sync_with_stdio(false);//Optimize input and output int ncase;//Define the number of test groups cin>>ncase; while(ncase--) { cin>>n>>e;//Given the number of vertices and edges mid_i=0; init();//Initialization for(int i=0; i<e; i++) { int v,w,d; cin>>v>>w>>d; bian[i].d=d; bian[i].v=v; bian[i].w=w;//Build a map bian[i].is_delete=false; } sort(bian,bian+e,cmp);//sort int sum=kruskal(1);//Get the minimum weight and mark the edge of the minimum spanning tree int tsum = MAXNUM; for(int i=0;i<mid_i;i++) { //cout<<mid_i<<endl; init();//Each initialization bian[MST_id[i]].is_delete=true;//Delete an edge of the minimum spanning tree tsum=min(kruskal(0),tsum);//Update the minimum value bian[MST_id[i]].is_delete=false;//Restore this edge } if(tsum==sum)//If the number is greater than 0, it exists { cout<<"Yes"<<endl; } else cout<<"No"<<endl; } }
The second is to use Puri to find the largest edge in the tree to see if there is an equivalent in the original image. If there is, it means that it is not unique.
O(n^2)
#include<iostream>//Import input and output stream functions #include<string.h>//Use memset using namespace std;//Import standard namespace #define MAXN 505//Define the maximum number of fixed points #define MAXNUM 0x3f3f3f3f//Define infinity int vis[MAXN];//Access the tag array int graph[MAXN][MAXN];//Matrix graph int n,e;//Number of vertices, number of edges int low[MAXN];//Save the vertex of the built tree to the minimum value of each point int MST[MAXN][MAXN];//The minimum value on the path from i to j int is_MST[MAXN][MAXN];//Whether it is in the tree int pre[MAXN];//Another node on the edge of the determined point int csum=MAXNUM; int sum=0; void init() { memset(graph, 0x3f, sizeof(graph));//Initialize the graph for(int i=0;i<=n;i++) graph[i][i]=0;//Set yourself and yourself to 0 memset(MST,0,sizeof(MST));//initialize to 0 memset(is_MST,0,sizeof(is_MST));//initialize to 0 csum=MAXNUM; sum=0; } bool prim(int s)//prim algorithm { for(int i=1;i<=n;i++) { low[i]=graph[s][i];//The distance from each point to s pre[i]=s;//The direct predecessor of each point is s vis[i]=0;//Initialize that each point has not been visited } vis[s]=1;//The s point has been set and visited for(int j=1;j<n;j++)//loop n-1 times { int tmin=MAXN;// int fa=0;// int ti = -1; for(int i=1;i<=n;i++) { if(vis[i]==0&&low[i]<tmin) { tmin=low[i]; ti = i; } }//Find the smallest low and subscript sum+=tmin; vis[ti]=1;//Set as found fa=pre[ti];//Take out another point on the side where the point ti is located is_MST[ti][fa]=is_MST[fa][ti]=1;//Mark this edge as in the tree for(int i=1;i<=n;i++) { if(vis[i]==1&&i!=ti) { MST[i][ti]=MST[ti][i]=max( MST[i][fa],low[ti]);//Update the largest point from other points in the tree to the point just found the largest edge on the path } if(!vis[i]&&low[i]>graph[ti][i])//If it has not been visited, s relax low { low[i]=graph[ti][i]; for [i] = ti; } } } for(int i=1;i<=n;i++) { for(int j=1;j<i;j++) { if(is_MST[i][j]==0&&MST[i][j]!=MAXNUM)//If there is an edge and it is not in the tree { //res=min(res,mst-path[i][j]+g[i][j]); Find the specific csum csum=min(csum,sum-MST[i][j]+graph[i][j]);//Find the next smallest spanning tree if(graph[i][j]==MST[i][j])//If there is an equivalent maximum edge in the original graph, it must exist { //return true; } } } } return false; } intmain() { ios::sync_with_stdio(false); int ncase; cin>>ncase; // ios::sync_with_stdio(false); while(ncase--) { cin>>n>>e; init(); for(int i=0;i<e;i++) { int v,w,d; cin>>v>>w>>d; graph[v][w]=d; graph[w][v]=d; // cout<<i<<endl; }//Build a map prim(1); if(sum==csum)//If the original is the same as the new one, then output yes { cout<<"Yes"<<endl; } else { cout<<"No"<<endl; } } return 0; }
Or use that sentence sparingly.
Dot more with Kruskal