• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
KのMidGard
人是人的一场雨,你终将独自前行。
博客园    首页    新随笔    联系   管理    订阅  订阅

[POJ2054]Color A Tree

题目大意:给出有N=1000个结点的树和点权,为结点 i 染色需要一单位时间,花费为染色时刻 T[i] * 点权W[i] ,只有为父亲染过色才能为孩子染色,求为所有结点染色最小花费

 

题目大意:多组数据,给出有N<=1000个结点的树和点权,为结点 i 染色需要一单位时间,花费为染色时刻 T[i] * 点权W[i] ,只有为父亲染过色才能为孩子染色,求为所有结点染色最小花费

看了评论才想起来是调整法证明的贪心:

  如果现有染色序列 A xxxx…k个结点…xxx B

  将其调整为    B A xxxx…k个结点…xxx

  则染色时刻变化为 T[A]   -> T[A]+1

           T[K……] -> T[K……]+1

           T[B]   -> T[B]-(k+1)

  则染色代价的变动 Δcost = + ∑点权W[A和K……] * 变动时刻1 - 点权W[B] * 变动时刻(k+1)

  那么当且仅当 Δcost<0 时,后一种方案比前者更优

  把 Δcost 变换一下 Δcost<0 推出 ∑W[AK..]-W[B]*(k+1) < 0

                  ∑W[AK..] < W[B]*(k+1)

                  ∑W[AK..] / (k+1) < W[B] / 1

  即是说当 W[B] >∑W[AK..] / (k+1) 时,将B放在A前染色会更优

  为每个结点设P[B]=∑W[B] / kB,当P[B]为当前最大时,将B与其父F合并,合并后的结点F’

  P[F'] = (∑W[B]+∑W[F]) / (kB + kF)

  W[F']=∑W[B]+∑W[F]

  kF' = kB + kF

  花费为∑W[B]

  P.S.可以用堆维护取最大值的过程,优化时间

#include<cstdio>
#include<cstring>
#include<iostream>
#define N 1500
using namespace std;
int n,m,root,w[N],f[N],s[N],res,id[N],son[N];
float p[N];
void swap(int i,int j){id[i]^=id[j];id[j]^=id[i];id[i]^=id[j];}
void heapify(int st,int end){
int t;
while((st<<1) < end){
if(p[id[st<<1]] > p[id[(st<<1)+1]]) t=(st<<1);
else t=(st<<1)+1;
if(p[id[t]] < p[id[st]]) break;
swap(st,t);
st=t;
}
if((st<<1) == end && p[id[st]] < p[id[end]]) swap(st,end);
}
int father(int i){
if(son[i]==i) return i;
else return son[i]=father(son[i]);
}
int main(){
int i,j,k,t,u,v;
while(scanf("%d%d",&n,&root),n&&root){
memset(son,0,sizeof(son));
res=0;
for(i=1;i<=n;i++){
scanf("%d",&w[i]);
s[i]=1;res+=w[i];
son[i]=id[i]=i;
p[i]=float(w[i]);
}
for(i=1;i<n;i++){
scanf("%d%d",&j,&k);
f[k]=j;
}
id[root]=n;
m=n-1;
for(i=m/2;i>0;i--) heapify(i,m);
i=m;
while(i--){
while(son[id[1]]!=id[1]){
id[1]=id[m--];
heapify(1,m);
}
t=id[1];
k=father(f[t]);
res+=w[t]*s[k];
if(k!=root){
son[k]=t;
s[t]+=s[k];
w[t]+=w[k];
f[t]=f[k];
p[t]=((float)(w[t])/(float)(s[t]));
heapify(1,m);
}
else{
s[k]+=s[t];
son[t]=root;
}
}
printf("%d\n",res);
}
return 0;
}



posted @ 2011-11-02 23:43  风行狩  阅读(1361)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3