现在有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();
}