<题目链接>

题目大意:

一个 $n$ 个节点 $m$ 条边的无向连通图,每条边有一个边权 $w_i$。现在她想玩一个游戏:选取一个 “重要点” S,然后选择性删除一些边,使得原图中所有除 S 之外度为 1 的点都不能到达 S。定义删除一条边的代价为这条边的边权,现在 Rinne 想知道完成这个游戏的最小的代价。(2≤S≤N≤10^5,M=N−1,保证答案在 C++ long long 范围内) 
解题分析:
因为该无向图连通,并且$n=m+1$,所以该图一定是一颗树。我们可以用树形DP解决本题。题目意思就是要我们删除该树中除$u$以外的所有叶子节点(如果u不为叶子节点的话,就是删除所有的叶子节点)的最小代价。很容易想到转移方程,用$cost[u]$表示删除以u为根的子树中所有叶子的最小代价,如果v直接与叶子相连的话,肯定要删除v--->叶子的这条边,所以所有的叶子节点的点权初始化为无穷大。然后就是利用树中的关系转移,对于以$u$为根的子树来说,$v$是它的一个直接相连的子节点,如果以v为根的子树中有叶子,则有两种情况删除。一:直接删除$u-->v$直接相连的这条边;二:不删除$u-->v$的这条边,删除以$v$为根的子树中的边,使v中的叶子节点不可到达$u$节点。这两种情况取最小值即可。同时本题用最大流也能够很容易解决。
树形DP
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. typedef long long ll;
  5. const int N = 1e5+;
  6. struct Edge{int to;ll w;};
  7. vector<Edge>G[N];
  8. int n,m,s;
  9. ll cost[N];
  10.  
  11. void dfs(int u,int fa){
  12. if(G[u].size()== && u!=s) //叶子节点的权值置为无穷
  13. cost[u]=1e18;
  14. for(int i=;i<G[u].size();i++){
  15. int v=G[u][i].to;
  16. if(v==fa)continue;
  17. dfs(v,u);
  18. cost[u]+=min(cost[v],G[u][i].w); //就是要删除以v为根的子树中的叶子所有叶子节点的最小代价
  19. }
  20. }
  21. int main(){
  22. scanf("%d%d%d",&n,&m,&s);
  23. for(int i=;i<=m;i++){
  24. int u,v;ll w;scanf("%d%d%lld",&u,&v,&w);
  25. G[u].push_back(Edge{v,w});
  26. G[v].push_back(Edge{u,w});
  27. }
  28. dfs(s,);
  29. printf("%lld\n",cost[s]);
  30. }
最大流Dinic
以S为汇点,再建立一个超级源点,连上所有的叶子节点(除S以外),然后直接跑一遍最大流即可。
下面的是两种最大流的板子:
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. typedef long long ll;
  5.  
  6. const int N = 1e5+;
  7. const ll INF = 1e18;
  8.  
  9. int n, m, S;
  10. int deg[N];
  11.  
  12. struct Dinic
  13. {
  14. struct edge{ int from,to;ll cap,flow; }; //cap-flow才是这条边的真实流量
  15. vector<edge>es;
  16. vector<int>G[N];
  17. bool vis[N];
  18. int dist[N],iter[N];
  19. void init(int n){
  20. for(int i=; i<=n+; i++)G[i].clear();
  21. es.clear();
  22. }
  23. void addedge(int from,int to,ll cap){
  24. es.push_back((edge){from,to,cap,}); //将边存储的边表
  25. es.push_back((edge){to,from,,});
  26. int x=es.size();
  27. G[from].push_back(x-); //G[u][i]记录以u为顶点的第i条边的反边在es中的编号
  28. G[to].push_back(x-);
  29. }
  30. bool BFS(int s,int t){ //bfs将该图划分成分层图
  31. memset(vis,,sizeof(vis));
  32. queue <int> q;
  33. vis[s]=;
  34. dist[s]=;
  35. q.push(s);
  36. while(!q.empty()){
  37. int u=q.front();q.pop();
  38. for(int i=; i<G[u].size(); i++){
  39. edge &e=es[G[u][i]];
  40. if(!vis[e.to]&&e.cap>e.flow){
  41. vis[e.to]=;
  42. dist[e.to]=dist[u]+;
  43. q.push(e.to);
  44. }
  45. }
  46. }
  47. return vis[t];
  48. }
  49. int DFS(int u,int t,ll f){
  50. if(u==t||f==)return f;
  51. int nowflow=,d;
  52. for(int &i=iter[u]; i<G[u].size(); i++){
  53. edge &e=es[G[u][i]];
  54. if(dist[u]+==dist[e.to]&&(d=DFS(e.to,t,min(f,e.cap-e.flow)))>){
  55. e.flow+=d; //正边真实流量-d
  56. es[G[u][i]^].flow-=d; //反边真实流量+d
  57. nowflow+=d; //得到现在搜得的能够流入汇点的流量
  58. f-=d; //找到一条增广路之后,减去这条路的流量,然后继续从这个顶点的其它边开始寻找增广路
  59. if(f==)break;
  60. }
  61. }
  62. return nowflow;
  63. }
  64. int Maxflow(int s,int t){
  65. int flow=;
  66. while(BFS(s,t)){
  67. memset(iter,,sizeof(iter));
  68. int d=;
  69. while(d=DFS(s,t,INF))flow+=d;
  70. }
  71. return flow;
  72. }
  73. }dinic;
  74.  
  75. void Get_Graph(){
  76. scanf("%d %d %d", &n, &m, &S);
  77. for (int i = ; i <= m; ++i) {
  78. int u, v; ll w;
  79. scanf("%d %d %lld", &u, &v, &w);
  80. deg[u]++; deg[v]++;
  81. dinic.addedge(u, v, w); dinic.addedge(v, u, w);
  82. }
  83.  
  84. for (int i = ; i <= n; ++i)
  85. if (deg[i] == && i != S) dinic.addedge(, i, INF); //建一个超级源点,流向所有度数为1的点(除s以外)
  86. }
  87.  
  88. int main(){
  89. Get_Graph();
  90. cout<<dinic.Maxflow(,S)<<endl;
  91. }

能够记录边的容量

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3.  
  4. typedef long long ll;
  5.  
  6. const int N = + ;
  7. const ll INF = 1e18;
  8. int n, m, S;
  9. int deg[N];
  10.  
  11. struct edge {
  12. int to, rev; ll cap;
  13. edge(int _to, ll _cap, int _rev) { to = _to, cap = _cap, rev = _rev; }
  14. };
  15. vector<edge> G[N];
  16.  
  17. inline void add_edge(int from, int to, ll cap) {
  18. G[from].push_back(edge(to, cap, G[to].size()));
  19. G[to].push_back(edge(from, , G[from].size() - ));
  20. }
  21.  
  22. void init() {
  23. scanf("%d %d %d", &n, &m, &S);
  24. for (int i = ; i <= m; ++i) {
  25. int u, v; ll w;
  26. scanf("%d %d %lld", &u, &v, &w);
  27. deg[u]++; deg[v]++;
  28. add_edge(u, v, w); add_edge(v, u, w);
  29. }
  30.  
  31. for (int i = ; i <= n; ++i)
  32. if (deg[i] == && i != S) add_edge(, i, INF); //建一个超级源点,流向所有度数为1的点(除s以外)
  33. }
  34.  
  35. struct Dinic {
  36. int level[N], iter[N];
  37. queue <int> que;
  38.  
  39. inline void bfs(int s) {
  40. memset(level, -, sizeof level);
  41. level[s] = ; //将图划分为层次图
  42. que.push(s);
  43.  
  44. while (!que.empty()) {
  45. int u = que.front(); que.pop();
  46. for (int i = ; i < G[u].size(); ++i) {
  47. edge &e = G[u][i];
  48. if (e.cap > && level[e.to] < ) {
  49. level[e.to] = level[u] + ;
  50. que.push(e.to);
  51. }
  52. }
  53. }
  54. }
  55.  
  56. ll dfs(int u, int t, ll f) {
  57. if (u == t) return f;
  58.  
  59. for (int &i = iter[u]; i < G[u].size(); ++i) {
  60. edge &e = G[u][i];
  61. if (e.cap > && level[e.to] > level[u]) {
  62. ll d = dfs(e.to, t, min(f, e.cap));
  63. if (d > ) {
  64. e.cap -= d;
  65. G[e.to][e.rev].cap += d;
  66. return d;
  67. }
  68. }
  69. }
  70. return ;
  71. }
  72.  
  73. ll max_flow(int s, int t) {
  74. ll flow = ;
  75. for (;;) {
  76. memset(iter, , sizeof iter);
  77. bfs(s);
  78. if (level[t] < ) return flow;
  79. ll f;
  80. while ((f = dfs(s, t, INF)) > ) flow += f;
  81. }
  82. }
  83. }dinic;
  84.  
  85. int main() {
  86. init();
  87. cout << dinic.max_flow(, S) << endl; //S为汇点
  88. }

不能记录边的容量

Nowcoder contest 370F Rinne Loves Edges (简单树形DP) || 【最大流】(模板)的更多相关文章

  1. Nowcoder contest 370H Rinne Loves Dynamic Graph【分层图最短路】

    <题目链接> 题目大意:Rinne 学到了一个新的奇妙的东西叫做动态图,这里的动态图的定义是边权可以随着操作而变动的图.当我们在这个图上经过一条边的时候,这个图上所有边的边权都会发生变动. ...

  2. Nowcoder contest 370B Rinne Loves Graph 【分层图最短路】

    <题目链接> 题目大意: Island 是有一些奇怪的城镇和道路构成的(题目需要,游戏党勿喷),有些城镇之间用双向道路连接起来了,且每条道路有它自己的距离.但是有一些城镇已经被派兵戒严,虽 ...

  3. poj 2342 Anniversary party 简单树形dp

    Anniversary party Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3862   Accepted: 2171 ...

  4. hdu 1520Anniversary party(简单树形dp)

    Anniversary party Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  5. hdu4705 Y 简单树形DP 2013多校训练第十场 J题

    题意:求一棵树中不在一条链中的三个点的对数. 转化一下,用总对数减去在一条链上的三点对数即可. 考虑经过根节点,然后可能是不同的子树中各选一个:或者是子树中选一个,然后当前节点为根的子树以外的节点选一 ...

  6. HDU 4705 Y (2013多校10,1010题,简单树形DP)

    Y Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submiss ...

  7. [10.27_P2] 统计损失 (简单树形DP)

    树形DP 简单题 Description 给定一棵树,每个节点有一个值.对于一条路径,它的值为路径上所有点的值的乘积.求出树上所有路径的值的和. 注意:单个点也算一条路径. Input 第 1 行一个 ...

  8. hdu 1054 Strategic Game (简单树形DP)

    Strategic Game Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  9. [Luogu P1122]最大子树和 (简单树形DP)

    题面 传送门:https://www.luogu.org/problemnew/show/P1122 Solution 这是一道简单的树形DP题. 首先,我们可以转换一下题面,可以发现,题目要求我们求 ...

随机推荐

  1. 尚硅谷《全套Java、Android、HTML5前端视频》

    尚硅谷<全套Java.Android.HTML5前端视频> (百万谷粉推荐:史上最牛.最适合自学的全套视频.资料及源码) [尚硅谷官网资料导航] 谷粒学院在线学习:http://www.g ...

  2. Confluence 6 修改日志文件的大小数量和级别

    修改日志文件的大小和数量 在默认的情况下,Confluence 将会保持 5 个日志文件,每一个日志文件的大小超过 20 MB 的时候将会被重写. 你可以修改默认日志文件的大小和数量,通过编辑 < ...

  3. Android UiAutomator

    UiAutomator是一个做UI测试的自动化框架.<Android自动化测试框架>中已有详细介绍,这里就不再累赘了. 一.首先了解自动化测试流程 自动化需求分析 测试用例设计 自动化框架 ...

  4. 基于DBUtils实现数据库连接池

    小知识: 1.子类继承父类的三种方式 class Dog(Animal): #子类 派生类 def __init__(self,name,breed, life_value,aggr): # Anim ...

  5. Solver Of Caffe

    本文旨在解决如何编写solver文件. Solver的流程: 1.     设计好需要优化的对象,以及用于学习的训练网络和用于评估的测试网络.(通过调用另外一个配置文件prototxt来进行) 2.  ...

  6. 怎么编辑PDF,如何给PDF加水印

    在使用PDF文件的时候,往往会用到PDF编辑器来修改,那么,在使用PDF编辑器修改文件的时候,想要在文件中添加水印,这该怎么操作呢,不会的小伙伴可以看看下面的文章了哦,说不定就会了. 1.打开运行PD ...

  7. vue中引入css文件

    两种方式引入css文件,一种是直接在main.js中引入(也可以在其他的.vue文件中的<script></script>标签中),即下面这种写法: import 'eleme ...

  8. easyui 布局之window和panel一起使用时,拉动window宽高时panel不跟随一起变化

    项目开发中布局是每一个组件都由最外层的window和内部的至少一个panel组成,其他的细小组件再依次放到panel中. 问题:当拉动外部的window时我们希望内部的panel的宽高也跟着变化,但是 ...

  9. selenium 操作键盘

    send_keys(Keys.ENTER) 按下回车键send_keys(Keys.TAB) 按下Tab制表键send_keys(Keys.SPACE) 按下空格键spacesend_keys(Kye ...

  10. CentOS安装jdk的三种方法

    方法一:手动解压JDK的压缩包,然后设置环境变量 方法二:用yum安装JDK,(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及CentOS中的 ...