P4189 [CTSC2010]星际旅行 (退流思想)
作者:互联网
P4189 [CTSC2010]星际旅行
分析:
对于只求一个点来说,因为题中保证了每个星球的hi大于等于度数。
也就是说,从一个点出发,保证可以遍历每一条边。
于是贪心地将能遍历到的边都遍历了,回溯的时候,将两个端点的h取min,累入答案里(在这两个点中重复走min次,贡献是min*2)
但题中要求每一个点。
考虑怎么利用已求出的点转移到未知的点。
现在已知u,要推v。
1. h [ u ]>0 :从u走到v,ans++(原来是以u为终止点,现在改成v,如果u可以再出去的话,肯定要从u再走回v)
2. h [ u ]==0
这时候又分两种情况:
因为终点最后是v,所以v到u的流肯定是要改的,改成什么呢?
1.v的儿子节点h非0,将v ->u 改成 v->son[v] son[v]->v,这样会使ans++
2.不能通过儿子使得ans++了,只能直接退掉这条边,ans - -。
#include<bits/stdc++.h> using namespace std; #define N 50005 #define ri register int int h[N],son[N],n,tot=0,ans[N]; vector<int> e[N]; void dfs1(int u,int ff) { for(ri i=0;i<e[u].size();++i){ int v=e[u][i]; if(v==ff) continue; dfs1(v,u); int tmp=min(h[u],h[v]); tot+=tmp*2; h[u]-=tmp; h[v]-=tmp; if(h[v]) son[u]=v; } } void dfs2(int u,int ff) { ans[u]=tot; int fl=0; for(ri i=0;i<e[u].size();++i){ int v=e[u][i]; if(v==ff) continue; if(h[u]) fl=1,tot++,h[u]--; else if(son[v]) fl=2,tot++,h[son[v]]--; else fl=3,tot--,h[v]++; dfs2(v,u); if(fl==1) tot--,h[u]++; else if(fl==2) tot--,h[son[v]]++; else tot++,h[v]--; } } int main() { scanf("%d",&n); for(ri i=1;i<=n;++i) scanf("%d",&h[i]); for(ri i=1;i<=n-1;++i){ int a,b; scanf("%d%d",&a,&b); a++,b++; e[a].push_back(b),e[b].push_back(a); h[a]--; h[b]--; tot+=2;//相当于遍历一遍 每条边都参与了2的贡献 } dfs1(1,0); dfs2(1,0); for(ri i=1;i<=n;++i) printf("%d\n",ans[i]); }View Code
标签:退流,min,int,++,son,P4189,遍历,ans,CTSC2010 来源: https://www.cnblogs.com/mowanying/p/11808638.html