考试9.5
Posted xwww666666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了考试9.5相关的知识,希望对你有一定的参考价值。
3>警察叔叔
题面真皮,复制自题解
考点:MST+树的遍历
题目大意:
给定一个无向有权图,
首先一个最小生成树 MST,从 MST 中选取一个度数大于 1 的点 作为根 K,
使每颗子树及该子树到根的边权之和方差最小。
输出 K 和最小方差的值。
由于N 比较大,所以只能通过 Kruskal 求MST,
接下来任选一个点作为根,进行一次遍历。
记录 w[i]表示以 i 点作为根的子树的边权之和。
然后依次枚举每一个点 i,该点的子树权值可以直接求出,
而以它父亲作为根的子树需要特殊处理。
这颗特殊子树的权值为最小生成树总权值减去该点权值 w[i]。
然后计算出方差,最后选取所有点当中最小方差的那个点即可。
时间复杂度:O(MlogM+N)
代码也不长,就是小数烦人
#include<cstdio> #include<cstdlib> #include<vector> #include<queue> #include<cstring> using namespace std; int n,m; const int N=40003; struct node int v;double w; bool operator < (const node & o) const return w>o.w; node(int vv,double ww) v=vv,w=ww; node() ; vector <node> g[N]; struct nd int u,v;double w; bool operator < (const nd & o) const return w>o.w; ; int f[N]; int find(int x) return !f[x]?x:f[x]=find(f[x]); void MST() priority_queue <nd> q; scanf("%d%d",&n,&m); nd t; while(m--) scanf("%d%d%lf",&t.u ,&t.v ,&t.w ); q.push(t); int cnt=1; while(!q.empty() && cnt<n) t=q.top() ;q.pop() ; int fu=find(t.u ),fv=find(t.v ); if(fu==fv) continue; f[fu]=fv,cnt++; g[t.u ].push_back(node(t.v ,t.w )); g[t.v ].push_back(node(t.u ,t.w )); int fa[N],g_sz[N]; double son[N],gg[N]; void dfs(int nw,int pre) fa[nw]=pre; g_sz[nw]=g[nw].size() ; for(int i=0;i<g_sz[nw];i++) int v=g[nw][i].v ; if(v==pre) continue; dfs(v,nw); son[nw]+=son[v]+g[nw][i].w ; int main() MST(); dfs(1,0); double ans=-1;int pos=0; for(int i=1;i<=n;i++) if(g_sz[i]==1) continue; double ave=son[1]/g_sz[i]; double check=0; for(int j=0;j<g_sz[i];j++) int v=g[i][j].v ; double t; if(v==fa[i]) t=son[1]-son[i]; else t=son[v]+g[i][j].w ; t-=ave; check+=t*t; if(ans==-1 || check<ans) ans=check,pos=i; printf("%d",pos); return 0;
记住这里的ans,
如果不知道什么是最大值,就不要瞎设,1e18都过不了。
不如老老实实-1
以上是关于考试9.5的主要内容,如果未能解决你的问题,请参考以下文章