SRM 638 DIV2 CandleTimerEasy

13 篇文章 0 订阅
11 篇文章 0 订阅

现在有n-1个蜡烛,如果点燃了长度为L的蜡烛的一段,那么就需要L个单位时间将这根蜡烛烧完。如果在蜡烛的两端同时点火,那么就只要一半的时间。把蜡烛作为边摆放成一棵有n个节点树,每个节点都是一根或多根蜡烛的一端。在0时刻可以选择任意一个或多个度为1的节点点火,那么经过一定的时间所有的蜡烛都会被燃烧殆尽。注意,如果火焰燃到了一个节点,那么所有以该节点作为端点的蜡烛都会点上火。求对于0时刻不同的点蜡烛的方式,有多少不同的燃完所有蜡烛的时间。

思路

<1>因为点的个数只会有20个,所以直接枚举度为一的节点有复杂度为 220
<2>又因为本题蜡烛的燃烧遵守最后一根烧好了才算烧完故只需要知道最后一个蜡烛何时烧好可以所以用迪杰斯特拉n*log(n)的计算
<3>对于可能从两端都被点燃的蜡烛我们可以再迪杰斯特拉过程中记录每个节点燃烧完其相邻所以蜡烛所用的额外时间其时间为一条蜡烛两个端点被点燃的时间之差的1/2,即|ar_t[now]-ar_t[nxt]|/2中最大的值

void check(int S){
    while(!Q.empty())Q.pop();
    int j=0,mx=0;
    for(int i=0;i<=n;i++)ar_t[i]=-1,ex_t[i]=0;
    for(int i=0;i<num;i++)if(S&(1<<i))Q.push((node){v[i],0});
    while(!Q.empty()){
        nw=Q.top();Q.pop();
        int x=nw.t,c=nw.c;
        if(~ar_t[x])continue;//如果已经到达过了
        ar_t[x]=c;
        for(int i=0;i<G[x].size();i++){
            int to=G[x][i].t,co=G[x][i].c;
            int C=c+co;
            if(ar_t[to]==-1)Q.push((node){to,C});
            else{
                ex_t[to]=max(ex_t[to],abs(C-ar_t[to])/2);//更新ex_t[to]
                if(C<ar_t[to])ar_t[to]=C;//最短路中的更新
            }
        }
    }
    for(int i=0;i<=n;i++)mx=max(mx,ar_t[i]+ex_t[i]);
    mark.insert(mx);//使用set来mark
}
int differentTime(vector <int> A, vector <int> B, vector <int> L){
    num=0;n=A.size();
    mark.clear();
    for(int i=0;i<n;i++){
        G[A[i]].push_back((node){B[i],2*L[i]});
        G[B[i]].push_back((node){A[i],2*L[i]});
        //事先将长度变为两倍可以直接用int来计算
    }
    for(int i=0;i<=n;i++)if(G[i].size()==1)v[num++]=i;
    for(int i=1;i<1<<num;i++)check(i);
    return mark.size();
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值