$Poj3585\ Accumulation Degree$ 树形$DP/$二次扫描与换根法
Description
有一个树形的水系,由n-1条河道与n个交叉点组成.每条河道有一个容量,联结x与y的河道容量记为c(x,y),河道的单位时间水量不能超过它的容量.有一个结点是整个水系的发源地,可以源源不断地流出水,为源点.树中度为1的点是入海口,可以吸收无限多的水,为汇点.待整个水系稳定时,每条河道中的水都以单位时间固定的水量流向固定的方向.整个水系的流量就定义为源点单位时间发出的水量.
求哪个点作为源点时,整个水系的流量最大.
Sol
最朴素的做法就是枚举源点,再树形DP,更新答案.复杂度是O(n2)的,不能接受.
推想:某点为源点时的流量可以由其他点为源点时的流量推出
d[x]表示x的度,f1[x]表示以x为根的树的最大流量,f2[x]表示以x为源点时水系的最大流量,y是x的子结点
首先任意选取一个点作为源点(root),一次树形DP算出所有的f1[x]
具体的转移: if(d[y]==1)f1[x]+=c(x,y) else f1[x]+=min(f1[y],c(x,y))
现在已知f2[x],可以推出f2[y]:
f2[y]包括两个部分:
1.流向x,(没错x由父变子hhh),这部分的流量:
if(d[x]==1) 为c(x,y) else 为f2[x]-min(f1[y],c(x,y))
2.流向原来就是它的子结点的点,这部分的流量就是f1[y]
over!
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define Rg register
#define il inline
#define mem(a,b) memset(a,b,sizeof(a));
#define go(i,a,b) for(Rg int i=a;i<=b;++i)
using namespace std;
il int read()
{
int x=,y=;char c=getchar();
while(c<''||c>''){if(c=='-')y=-;c=getchar();}
while(c>=''&&c<=''){x=(x<<)+(x<<)+c-'';c=getchar();}
return x*y;
}
const int N=;
int T,n,ans,d[N],f1[N],f2[N];
bool vis[N];
struct node{int y,w;};
vector<node> c[N];
il void init()
{
ans=;
mem(vis,);mem(d,);mem(f1,);mem(f2,);
go(i,,n)c[i].clear();
}
il void dp1(int x)
{
vis[x]=;
int hhh=c[x].size()-;
go(i,,hhh)
{
int y=c[x][i].y,w=c[x][i].w;
if(vis[y])continue;
dp1(y);
if(d[y]==)f1[x]+=w;
else f1[x]+=min(f1[y],w);
}
}
il void dp2(int x)
{
vis[x]=;
int hhh=c[x].size()-;if(hhh<)return;
go(i,,hhh)
{
int y=c[x][i].y,w=c[x][i].w;
if(vis[y])continue;
if(d[x]==)f2[y]=f1[y]+w;
else f2[y]=f1[y]+min(f2[x]-min(f1[y],w),w);
dp2(y);
}
}
int main()
{
T=read();
while(T--)
{
n=read();init();
go(i,,n-)
{
int x=read(),y=read(),z=read();
c[x].push_back((node){y,z});c[y].push_back((node){x,z});
++d[x],++d[y];
}
dp1();
f2[]=f1[];mem(vis,);
dp2();
go(i,,n)ans=max(ans,f2[i]);
printf("%d\n",ans);
}
return ;
}
随机推荐
- Card Hand Sorting 二进制枚举暴力
这个题其实由于只有4种花色的,那么每种花色排列的顺序,也不过是4!种,然后对于每种花色内部到底是升序还是降序,其实也可以直接暴力,一共也就4!*2^4种情况,然后直接进行排序就可以了,但是我们如何计算 ...
- Ext.FormPanel-----FieldSet的用法
Ext.form.FieldSet的常用配置项: 1.checkboxToggle : Mixed True表示在lengend标签之前fieldset的范围内渲染一个checkbox,或者送入一个D ...
- codeforces2B.The least round way 题解 动态规划/模拟
题目出处:http://codeforces.com/problemset/problem/2/B 题目描述 给你一个 \(n \times n\) 的二维数组,它包含的元素都是非负整数.你需要寻找一 ...
- CondaHTTPError: HTTP 000 CONNECTION FAILED
[root@localhost ~]# conda install samtools Solving environment: failed CondaHTTPError: HTTP 000 CONN ...
- 洛谷P2590 [ZJOI2008]树的统计 题解 树链剖分+线段树
题目链接:https://www.luogu.org/problem/P2590 树链剖分模板题. 剖分过程要用到如下7个值: fa[u]:u的父节点编号: dep[u]:u的深度: size[u]: ...
- H3C 帧中继基本概念
- HDU 2717 宽搜第一题、
题意:求n到k的最小路径, n有三种变法 n+1,n-1或者2*n: 贴个广搜的模版在这里把.... 总结一下:一般涉及到求最短路的话用宽搜 #include<iostream> #in ...
- dotnet 设计规范 · 抽象定义
严格来说,只有一个类被其他的类继承,那么这个类就是基类.在很多时候,基类的定义是提供足够的抽象和通用方法和属性.默认实现.在继承关系中,基类定义在上层抽象和底层自定义之间. 他们充当抽象实现的实现帮助 ...
- 【p083】传球游戏
Time Limit: 1 second Memory Limit: 50 MB [问题描述] 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏. 游戏规则是这样 ...
- linux Completions 机制
内核编程的一个普通模式包括在当前线程之外初始化某个动作, 接着等待这个动作结束. 这个动作可能是创建一个新内核线程或者用户空间进程, 对一个存在着的进程的请求, 或 者一些基于硬件的动作. 在这些情况 ...