牛客暑期第六场G /// 树形DP 最大流最小割定理
题目大意:
输入t,t个测试用例
每个测试用例输入n
接下来n行 输入u,v,w,树的无向边u点到v点权重为w
求任意两点间的最大流的总和
1.最大流最小割定理 即最大流等于最小割
2.无向树上的任意两点都可互达 也就是说 源点S可经其他任何点流到汇点T
设dist(x , y) 为在树上 x 到 y 的距离
由2能知道,S的总流量就是 n∑i=1 dis( s , i )
然后就是题解上的 S到其他各个点的距离 和 T到其他各个点的距离 中较小的即为最小割

举个栗子
4
1 2 3
1 3 4
3 4 5

通过树形DP
ll dis[MAXN], son[MAXN], dp[MAXN]; /// dis[ i ]为从 i 点向下的分支的长度总和
/// son[ i ]为从 i 点向下的总点数(包括它本身)
/// dp[ i ]为从 i 点出发去其他所有点的长度总和 void dfs1(ll u,ll f) /// 求dis[],son[]
{
son[u]=;
for(int i=;i<vec[u].size();i++) {
ll v=vec[u][i].F, w=vec[u][i].S;
if(v==f) continue;
dfs1(v,u);
son[u]+=son[v];
dis[u]+=dis[v]+son[v]*w;
}
} void dfs2(int u,int f) /// 通过dis[]进行树形DP
{
for(int i=;i<vec[u].size();i++) {
ll v=vec[u][i].F, w=vec[u][i].S;
if(v==f) continue;
dp[v]=dp[u]+(n-*son[v])*w;
dfs2(v,u);
}
}
...... dfs1(,); dp[]=dis[]; dfs2(,); ......
/*结果为
dis[] 16 0 5 0
son[] 4 1 2 1 dp[] 16 22 16 26
*/
可以转化为一个(姑且称之为)流量图

括号内的是到该点的总流量
那么 S到T的最大流 就是 两者总流量中 小的一个
sort(dp+,dp++n);
__int128 ans=;
for(int i=;i<n;i++)
ans += dp[i]*(n-i);
当某个点x的总流量是所有点中的最小值时
那么x与其他所有点的最大流就是x的总流量
所以这里可以直接贪心 排序一下
第 i 个点与后面比它(的总流量)小的所有点(n - i 个)直接取第 i 个
也可以不用 __int128 ,开个数组模拟一下
int ans[];
memset(ans,,sizeof(ans));
for(ll i=;i<n;i++) {
ans[] += dp[i]*(n-i);
int j=;
while(ans[j]>=) {
ans[j+] += ans[j]/;
ans[j++] %= ;
}
len=max(len,j);
}
printf("Case #%d: %lld",o,ans[len]);
for(int i=len-;i>=;i--) {
if(ans[i]>=) printf("%lld",ans[i]);
else if(ans[i]>=) printf("0%lld",ans[i]);
else printf("00%lld",ans[i]);
} printf("\n");
完整代码
#include <bits/stdc++.h>
#define P pair<ll,ll>
#define mp(i,j) make_pair(i,j)
#define F first
#define S second
#define MAXN 100005
#define ll long long
using namespace std; vector <P> vec[MAXN];
ll dis[MAXN], son[MAXN], dp[MAXN];
ll n, m, ans[MAXN]; void dfs1(ll u,ll f)
{
son[u]=;
for(int i=;i<vec[u].size();i++) {
ll v=vec[u][i].F, w=vec[u][i].S;
if(v==f) continue; dfs1(v,u); son[u]+=son[v];
dis[u]+=dis[v]+son[v]*w;
}
} void dfs2(int u,int f)
{
for(int i=;i<vec[u].size();i++) {
ll v=vec[u][i].F, w=vec[u][i].S;
if(v==f) continue; dp[v]=dp[u]+(n-*son[v])*w; dfs2(v,u);
}
} int main()
{
int t; scanf("%d",&t);
for(int o=;o<=t;o++) {
for(int i=;i<=n;i++) vec[i].clear();
memset(dis,,sizeof(dis));
memset(son,,sizeof(son));
memset(dp,,sizeof(dp)); scanf("%lld",&n);
for(int i=;i<n;i++) {
ll u,v,w; scanf("%lld%lld%lld",&u,&v,&w);
vec[u].push_back(mp(v,w));
vec[v].push_back(mp(u,w));
} dfs1(,); dp[]=dis[]; dfs2(,);
sort(dp+,dp++n); int len=;
memset(ans,,sizeof(ans));
for(ll i=;i<n;i++) {
ans[] += dp[i]*(n-i);
int j=;
while(ans[j]>=) {
ans[j+] += ans[j]/;
ans[j++] %= ;
}
len=max(len,j);
} printf("Case #%d: %lld",o,ans[len]);
for(int i=len-;i>=;i--) {
if(ans[i]>=) printf("%lld",ans[i]);
else if(ans[i]>=) printf("0%lld",ans[i]);
else printf("00%lld",ans[i]);
} printf("\n");
} return ;
}
数组模拟
#include <bits/stdc++.h>
#define P pair<int,int>
#define mp(i,j) make_pair(i,j)
#define F first
#define S second
#define MAXN 100005
using namespace std;
vector <P> vec[MAXN];
int son[MAXN];
int n, m;
__int128 dis[MAXN], dp[MAXN]; void dfs1(int u,int f)
{
son[u]=;
for(int i=;i<vec[u].size();i++) {
int v=vec[u][i].F, w=vec[u][i].S;
if(v==f) continue; dfs1(v,u); son[u]+=son[v];
dis[u]+=dis[v]+son[v]*w;
}
} void dfs2(int u,int f)
{
for(int i=;i<vec[u].size();i++) {
int v=vec[u][i].F, w=vec[u][i].S; if(v==f) continue; dp[v]=dp[u]+(n-*son[v])*w; dfs2(v,u);
}
} void print(__int128 ans)
{
if(ans>) print(ans/);
printf("%c",''+ans%);
} int main()
{
int t; scanf("%d",&t);
for(int o=;o<=t;o++) { for(int i=;i<=n;i++) vec[i].clear();
memset(dis,,sizeof(dis));
memset(son,,sizeof(son));
memset(dp,,sizeof(dp)); scanf("%d",&n);
for(int i=;i<n;i++) {
int u,v,w; scanf("%d%d%d",&u,&v,&w);
vec[u].push_back(mp(v,w));
vec[v].push_back(mp(u,w));
} dfs1(,); dp[]=dis[]; dfs2(,); sort(dp+,dp++n);
__int128 ans=;
for(int i=;i<n;i++)
ans += dp[i]*(n-i); printf("Case #%d: ",o);
print(ans);printf("\n");
} return ;
}
__int128
牛客暑期第六场G /// 树形DP 最大流最小割定理的更多相关文章
- run (牛客多校第二场)计数DP
链接:https://www.nowcoder.com/acm/contest/140/A来源:牛客网 题目描述 White Cloud is exercising in the playground ...
- 牛客练习赛32B Xor Path (树形dp)
时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524288K 64bit IO Format: %lld 题目描述 给定一棵n个点的树,每个点有权值.定义表示 ...
- [2019牛客多校第二场][G. Polygons]
题目链接:https://ac.nowcoder.com/acm/contest/882/G 题目大意:有\(n\)条直线将平面分成若干个区域,要求处理\(m\)次询问:求第\(q\)大的区域面积.保 ...
- 牛客多校第二场 G transform
链接:https://www.nowcoder.com/acm/contest/140/G White Cloud placed n containers in sequence on a axes. ...
- 二分图最佳匹配KM算法 /// 牛客暑期第五场E
题目大意: 给定n,有n间宿舍 每间4人 接下来n行 是第一年学校规定的宿舍安排 接下来n行 是第二年学生的宿舍安排意愿 求满足学生意愿的最少交换次数 input 2 1 2 3 4 5 6 7 8 ...
- 2019牛客竞赛第六场D Move 宏观单调,部分不单调
Move 题意 有k个体积相同的箱子,有个憨憨有固定的装箱策略,每次都只装可以装的重量中最大的东西,求箱子的最小提及 分析 看起来可以二分,但由于他的装箱策略有点蠢,所以只在宏观上满足单调性,在特别小 ...
- 牛客小白月赛3---G 旅游(树形dp)
题目链接:https://www.nowcoder.com/acm/contest/87/G 分析: 1.对于点cur,dp[cur][0]表示在该点住宿:dp[cur][1]表示其某个子结点住宿,自 ...
- 2019牛客多校第一场 E-ABBA(dp)
ABBA 题目传送门 解题思路 用dp[i][j]来表示前i+j个字符中,有i个A和j个B的合法情况个数.我们可以让前n个A作为AB的A,因为如果我们用后面的A作为AB的A,我们一定也可以让前面的A对 ...
- 【牛客】路径计数机 (树形dp 前缀和)
题目描述 有一棵n个点的树和两个整数p, q,求满足以下条件的四元组(a, b, c, d)的个数: 1.$1\leq a,b,c,d \leq n$ 2.点a到点b的经过的边数为p. 3.点c ...
随机推荐
- JAVA jar命令(一)-jar打包class文件
jar包本质上是将所有class文件.资源文件压缩打成一个包(也可以选择不压缩),可选择在jar包中生成META-INF/MANIFEST.MF文件,MANIFEST.MF是清单文件,里面可以记录主类 ...
- 【CSS】float
写在前面的话: 由于CSS内容比较多,小菜没有精力从头到尾讲一遍,只能有针对性的讲解. 如果读者理解CSS盒子模型,但对于浮动不理解,那么这篇文章可以帮助你. 小菜水平有限,本文仅仅是入门教程,不当之 ...
- thinkphp 缓存驱动
缓存驱动默认位于Think\Cache\Driver命名空间下面,目前已经提供了包括APC.Db.Memcache.Shmop.Sqlite.Redis.Eaccelerator和Xcache缓存方式 ...
- SPOJ:[DIVCNT3]Counting Divisors
题目大意:求1~N的每个数因子数的立方和. 题解:由于N过大,我们不能直接通过线性筛求解.我们可以采用洲阁筛. 洲阁筛的式子可以写成: 对于F(1~√n),可以直接线性筛求解. 对于,我们进行以下DP ...
- JZOJ5153:树形图求和
Description Input Output HINT 题解: 一种很直观的想法是通过矩阵生成树求树形图方法数ans以及不包含某一条边i的树形图方法数ans[i],则答案为Σ(ans-ans[i] ...
- 配置Dubbo Demo遇到的坑之一---找不到dubbo.xsd文件
原文地址:https://blog.csdn.net/qq_36654870/article/details/80603302 1.dubbo.xsd文件不能读取 因为阿里http://code.al ...
- css3 常用的属性
1.伪类选择符 Pseudo-Classes Selectors Selectors选择符 CSS Version版本 Description简介 E:link CSS1 设置超链接a在未被访问前的样 ...
- DLL和OCX注册
在注册DLL或者OCX的方法应该使用regsvr32.exe,使用得多了一定会觉得在cmd运行中写一长串东西很烦人吧!这里向大家介绍一种麻烦一次方便一生的方法.这个方法只要右击你想注册或者反注册的DL ...
- 网页开发人员收藏的16款HTML5工具
本文收集的20款优秀的 HTML5 Web 应用程序,值得添加到您的 HTML5 的工具箱中,他们能够帮助你开发前端项目更快.更容易. Initializr Initializr 是一个可以让你创建 ...
- MySQL 07章_子查询
子查询就是查询中还可以嵌套其他的查询,通常是内层查询的结果作为外层查询的条件来使用 执行循序,自内向外依次执行 一.内层查询返回“单列单行”的结果 -- 1.查询宋江的出生日期 SELECT TIME ...