最小生成树
翻了下之前做过的题,感觉都水的不行=_=||
The Unique MST
题意:判断最小生成树是否唯一。
先求出最小生成树权值ans,用vector记录用的边。
依次不用vector里记录的边求生成树,若权值等于ans,说明不唯一。
1 #include<iostream> 2 #include<cstring> 3 #include<vector> 4 #include<algorithm> 5 using namespace std; 6 7 int n,m; 8 struct edge 9 { 10 int u,v,w; 11 bool operator <(const edge &a) const { 12 return w<a.w; 13 } 14 }e[10010]; 15 int f[110]; 16 int ans; 17 vector<int>mst; 18 19 void init() 20 { 21 for(int i=0;i<=n;i++) 22 f[i]=i; 23 } 24 25 int gf(int x) 26 { 27 return x==f[x]?x:f[x]=gf(f[x]); 28 } 29 30 void unit(int x,int y) 31 { 32 int px=gf(x); 33 int py=gf(y); 34 f[px]=py; 35 } 36 37 void kru() 38 { 39 init(); 40 for(int i=0;i<m;i++) 41 { 42 if(gf(e[i].u)!= gf(e[i].v)) 43 { 44 mst.push_back(i); 45 ans+=e[i].w; 46 unit(e[i].u,e[i].v); 47 } 48 } 49 50 } 51 bool yesno() 52 { 53 for(int i=0;i<mst.size();i++) 54 { 55 int cost=0; 56 init(); 57 int k=0; 58 for(int j=0;j<m;j++) 59 { 60 if(mst[i]==j) continue; 61 if(gf(e[j].u)!=gf(e[j].v)) 62 { 63 cost+=e[j].w; 64 k++; 65 unit(e[j].u,e[j].v); 66 } 67 } 68 if(cost==ans&&k==n-1) return 1; 69 } 70 return 0; 71 } 72 int main() 73 { 74 int t; 75 cin>>t; 76 while(t--) 77 { 78 mst.clear(); 79 ans=0; 80 81 cin>>n>>m; 82 83 for(int i=0;i<m;i++) 84 cin>>e[i].u>>e[i].v>>e[i].w; 85 86 sort(e,e+m); 87 kru(); 88 if(yesno()) cout<<"Not Unique!\n"; 89 else cout<<ans<<endl; 90 91 } 92 }
Slim Span
题意:求生成树的最小边权差。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxe=10010; 4 struct Edge 5 { 6 int u,v,w; 7 bool operator <(const Edge &a)const 8 { 9 return w<a.w; 10 } 11 }e[maxe]; 12 int n,m; 13 int slim; 14 int f[110]; 15 int gf(int x) 16 { 17 return x==f[x]?x:f[x]=gf(f[x]); 18 } 19 void kruskal(int x) 20 { 21 int cnt=0,temp=0; 22 for(int i=0;i<=n;i++) f[i]=i; 23 int i; 24 for(i=x;i<m;i++) 25 { 26 int pu=gf(e[i].u); 27 int pv=gf(e[i].v); 28 if(pu!=pv) 29 { 30 cnt++; 31 f[pu]=pv; 32 if(cnt==n-1) break; 33 } 34 } 35 if(cnt!=n-1) return ; 36 temp=e[i].w-e[x].w; 37 if(x==0||temp<slim) slim=temp; 38 return ; 39 } 40 41 int main() 42 { 43 while(scanf("%d%d",&n,&m)&&(n||m)) 44 { 45 slim=-1; 46 for(int i=0;i<m;i++) 47 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); 48 sort(e,e+m); 49 for(int i=0;i+n-2<m;i++) // 50 { 51 kruskal(i); 52 } 53 printf("%d\n",slim); 54 } 55 }
Park Visit
题意:一个人逛公园,希望看p个景点,景点与路形成一棵树形图,问最少走多少路。
先求出树的直径:
从任意一点(一般取第一点)进行bfs,记录下边界a;
再从a进行bfs,直到边界,记录下长度,即直径。
然后,如果输入不大于直径,直接输出即可,
若大于直径,则除了直径上的点,其他要走的都要走一个来回,需要乘2
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 #include<cstdio> 6 using namespace std; 7 const int maxn=1e5+10; 8 vector<int>node[maxn]; 9 int n , m; 10 int start,mm; 11 void dfs(int per,int fro,int len) 12 { 13 if(len>mm) 14 { 15 mm=len; 16 start=per; 17 } 18 for(int i=0;i<node[per].size();i++) 19 if(node[per][i]!=fro) dfs(node[per][i],per,len+1); 20 } 21 int main() 22 { 23 int t; 24 scanf("%d",&t); 25 while(t--) 26 { 27 28 scanf("%d%d",&n,&m); 29 for(int i=0;i<=n;i++) node[i].clear(); 30 int x,y; 31 for(int i=0;i<n-1;i++) 32 { 33 scanf("%d%d",&x,&y); 34 node[x].push_back(y); 35 node[y].push_back(x); 36 } 37 start=mm=0; 38 dfs(1,0,0); 39 mm=0; 40 dfs(start,0,0); 41 42 int p; 43 for(int i=0;i<m;i++) 44 { 45 scanf("%d",&p); 46 if(p<=mm+1) printf("%d\n",p-1); 47 else printf("%d\n",mm+(p-mm-1)*2); 48 } 49 } 50 }
树中的最长路
题意:求树的直径。
另一种方法:记录每个点的最长路与次长路,不断更新。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=100010; 6 7 int md1[maxn],md2[maxn]; 8 //最长 次长 9 struct node 10 { 11 int v; 12 int nex; 13 }e[maxn*2]; 14 15 16 int head[maxn]; 17 int cnt; 18 19 void add(int u,int v) 20 { 21 e[cnt].v=v; 22 e[cnt].nex=head[u]; 23 head[u]=cnt++; 24 } 25 26 int dfs(int u,int pre) 27 { 28 int d; 29 for(int i=head[u];i!=-1;i=e[i].nex) 30 { 31 if(e[i].v==pre) continue; 32 d=dfs(e[i].v,u)+1; 33 if(d>md1[u]) //子树最长路大于父亲最长路径 34 { 35 md2[u]=md1[u]; 36 md1[u]=d; 37 } 38 else if(d>md2[u]) md2[u]=d; //子树路径只大于次长路径 39 } 40 return md1[u]; 41 42 } 43 int main() 44 { 45 int n; 46 int t; 47 while( scanf("%d",&n)!=EOF) 48 { 49 cnt=0; 50 int u,v; 51 memset(head,-1,sizeof(head)); 52 memset(md1,0,sizeof(md1)); 53 memset(md2,0,sizeof(md2)); 54 for(int i=1;i<n;i++) 55 { 56 scanf("%d%d",&u,&v); 57 add(u,v); 58 add(v,u); 59 } 60 dfs(1,0); 61 int ans=0; 62 for(int i=1;i<=n;i++) 63 ans=max(ans,md1[i]+md2[i]); 64 printf("%d\n",ans); 65 } 66 }
Buy or Build
题意:求最小生成树。有一些套餐可选,套餐内的边一共只需要一个价钱。
好像是紫书上的题目。二进制枚举套餐。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<algorithm> 5 #define ll long long 6 using namespace std; 7 vector<int> mst; 8 const int maxn=1010; 9 int qsize[10],qcost[10],q[10][maxn]; 10 int x[maxn],y[maxn]; 11 int f[maxn]; 12 int cnt,ans; 13 14 struct edge 15 { 16 int u; 17 int v; 18 int w; 19 bool operator < (const edge &a ) 20 { 21 return w<a.w; 22 } 23 }e[maxn*maxn]; 24 25 int t,n,m; 26 void init() 27 { 28 for(int i=0;i<=n;i++) 29 f[i]=i; 30 ans=0; 31 cnt=0; 32 mst.clear(); 33 } 34 35 int gf(int x) 36 { 37 return x==f[x]?f[x]:f[x]=gf(f[x]); 38 } 39 40 void uni(int a,int b) 41 { 42 int pa=gf(a); 43 int pb=gf(b); 44 f[pa]=pb; 45 } 46 47 int gd(int i,int j) 48 { 49 int dx=x[i]-x[j]; 50 int dy=y[i]-y[j]; 51 return dx*dx+dy*dy; 52 } 53 54 void add(int u,int v,int w) 55 { 56 e[cnt].u=u; 57 e[cnt].v=v; 58 e[cnt].w=w; 59 cnt++; 60 } 61 62 63 void krustal() 64 { 65 int coun=0; 66 for(int i=0;i<cnt;i++) 67 { 68 if(gf(e[i].u)!=gf(e[i].v)) 69 { 70 uni(e[i].u,e[i].v); 71 ans+=e[i].w; 72 mst.push_back(i); 73 coun++; 74 if(coun==n-1) break; 75 } 76 } 77 } 78 79 void mincost () 80 { 81 82 for(int s=1;s<(1<<m);s++) //枚举 83 { 84 int temp=0; 85 for(int i=0;i<=n;i++) f[i]=i; 86 for(int i=0;i<m;i++) if(s&(1<<i)) 87 { 88 temp+=qcost[i]; 89 for(int j=0;j<qsize[i];j++) 90 for(int k=j+1;k<qsize[i];k++) 91 if(gf(q[i][j])!=gf(q[i][k])) uni(q[i][j],q[i][k]); 92 } 93 int len=mst.size(); 94 for(int i=0;i<len;i++) 95 { 96 int j=mst[i]; 97 if(gf(e[j].u)!=gf(e[j].v)) 98 { 99 temp+=e[j].w; 100 uni(e[j].u,e[j].v); 101 } 102 } 103 ans=min(ans,temp); 104 } 105 106 107 } 108 109 int main() 110 { 111 scanf("%d",&t); 112 while(t--) 113 { 114 scanf("%d%d",&n,&m); 115 init(); 116 for(int i=0;i<m;i++) 117 { 118 scanf("%d%d",&qsize[i],&qcost[i]); 119 for(int j=0;j<qsize[i];j++) 120 scanf("%d",&q[i][j]); 121 } 122 for(int i=1;i<=n;i++) 123 { 124 scanf("%d%d",&x[i],&y[i]); 125 } 126 for(int i=1;i<n;i++) 127 for(int j=i+1;j<=n;j++) 128 add(i,j,gd(i,j)); 129 sort(e,e+cnt); 130 krustal(); 131 mincost(); 132 printf("%d\n",ans); 133 if(t) printf("\n"); 134 } 135 136 }
选了这几道重新码一下,其他基本都是很裸的模板题了。。。