LightOJ 1123 Trail Maintenance

题意:n个城市m天、每一天修一条道路,输出当前天数的最小生成树,但是这里有一个条件,就是说最小生成树必须包括全部n个城市,否则输出-1

思路:边数有6000如果每一天跑一次最小生成树的话就接近O(m^2logm)再加上数据量、是很可能会超时的、这时我们就得想想能不能删去一些边、这样在求最小生成树的时候就可以减少很多不必要的边,因为只有n(<=200)个城市,最多只会有n-1条边,那么哪种情况下的边可以删去呢?

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 const int qq=7000;
 7 int pre[500];
 8 struct Edge
 9 {
10     int u,v,w;
11     bool operator < (const Edge a)const{
12         return w<a.w;
13     }
14 }edge[qq];
15 int cnt;
16 int find(int x)
17 {
18     if(x==pre[x])    return x;
19     return pre[x]=find(pre[x]);
20 }
21 int kruscal(int n)
22 {
23     for(int i=1;i<=n;++i)
24         pre[i]=i;
25     int u,v,w;
26     int minx=0,count=1;
27     int ans=cnt;    //先记录当前所有的边数、 
28     for(int i=0;i<ans;++i){        //遍历所有的边、 
29         u=edge[i].u;v=edge[i].v;w=edge[i].w;
30         int x=find(u);
31         int y=find(v);
32         if(x==y){        //这种情况下是一定会删边的、 
33             edge[i]=edge[cnt-1];     
34             --cnt;        //因为开始已经将当前边数数值给ans了,所以不用担心遍历不到当前的所有边 
35             continue;    // 可以直接进行删边操作了、 
36         }    
37         ++count;        //记录当前的边数、 
38         pre[y]=x;
39         minx+=w;
40     }
41     if(count==n)    return minx;    //因为是开始count的初值是1,所以只需要判断当前边数等于n与否 
42     else    return -1;
43 }
44 int main()
45 {
46     int t;scanf("%d",&t);
47     int k=1;
48     while(t--){
49         int n,m;
50         scanf("%d%d",&n,&m);
51         int u,v,w;
52         cnt=0;
53         printf("Case %d:
",k++);
54         for(int i=0;i<m;++i){
55             scanf("%d%d%d",&u,&v,&w);
56             edge[cnt].u=u;edge[cnt].v=v;edge[cnt++].w=w;
57             sort(edge,edge+cnt);
58             printf("%d
",kruscal(n));
59         }
60     }
61     return 0;
62 }

在结构体内重载运算符的时候记得加return 记得加return 记得加return

重要事情说三遍、!!!

原文地址:https://www.cnblogs.com/sasuke-/p/5458029.html