思想很重要,题目给出了每个星球的Hi大于等于与该星球直接相连的星球数(即度数)。
就说明从0点出发,一定可以再回到0点。
在第一次dfs中把一些还可以加的流加入使得答案更大。因为图此时已经连通。
然后对于相邻的两个点,就一定至少有一个的度数为0。
在第二次dfs中运用“退流”思想,对于每一个点求出它的ans,即如果最终旅行结束在这个星球,最多可以使用时空隧道的次数。
(摘自这儿)
#include<bits/stdc++.h> #define N 50003 using namespace std; int read() { int x=0,f=1;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x*f; } struct EDGE{ int nextt,to; }w[N*2]; int tot=0,sum=0; int h[N],head[N],r[N],ans[N]; void add(int a,int b) { tot++; w[tot].nextt=head[a]; w[tot].to=b; head[a]=tot; } void dfs1(int x,int fa)//在已经确定了可以走一个来回后加入多的流 { for(int i=head[x];i;i=w[i].nextt) { int v=w[i].to; if(v==fa)continue; dfs1(v,x); int k=min(h[x],h[v]); sum+=k*2; h[x]-=k;h[v]-=k; if(h[v])r[x]=v;//表示x这个点有退自己父亲的流的机会 } } void dfs2(int x,int fa)//对于每一个点求ans { ans[x]=sum; int flagg; for(int i=head[x];i;i=w[i].nextt) { int v=w[i].to; if(v==fa)continue; if(h[x])flagg=1,h[x]--,sum++; else if(r[v])flagg=2,h[r[v]]--,sum++; else flagg=3,sum--,h[v]++;//退了到父亲的流 dfs2(v,x); if(flagg==1)h[x]++,sum--; else if(flagg==2)h[r[v]]++,sum--; else sum++,h[v]--; } } int main() { int n=read(); for(int i=1;i<=n;++i) h[i]=read(); for(int i=1;i<n;++i)//一定要遍历所有的边一个来回,然后可以证明最优情况肯定是遍历的所有边的 { int a=read()+1,b=read()+1; add(a,b);add(b,a);sum+=2; h[a]--;h[b]--; } dfs1(1,1); dfs2(1,1); for(int i=1;i<=n;++i) printf("%d ",ans[i]); }