标签:退流 min int ++ son P4189 遍历 ans 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
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。