题意: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:\n",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\n",kruscal(n)); 59 } 60 } 61 return 0; 62 }
在结构体内重载运算符的时候记得加return 记得加return 记得加return
重要事情说三遍、!!!
时间: 2024-10-13 23:10:30