标签:tor code div 特殊 输出 ring 最大 pre 处理
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
标签:tor code div 特殊 输出 ring 最大 pre 处理
原文地址:https://www.cnblogs.com/xwww666666/p/11470343.html