hdu2242(树形dp+tarjan+缩点)

hdu2242 http://acm.hdu.edu.cn/showproblem.php?pid=2242

给定n,m表示n个点,m条边

每个点有个权值

问我们删除两某条边(割边)后将图分为两个部分,要使得两个部分的权值之差最小

这题的弱化版本是在一棵树上删除某条边后后将图分为两个部分,要使得两个部分的权值之差最小。是用树形dp来做的

但是这道题目是个图,但是我们可以转化为树,即将图中的边连通分量求出来,然后缩成一个点,建出一个新的树图,那么就可以用树形dp来求解题目了.

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <algorithm>
  5 #include <iostream>
  6 #include <queue>
  7 #include <stack>
  8 #include <vector>
  9 #include <map>
 10 #include <set>
 11 #include <string>
 12 #include <math.h>
 13 using namespace std;
 14 typedef long long LL;
 15 const int INF = 1<<30;
 16 const int N = 10000 + 10;
 17 vector<int> g1[N],g2[N];
 18 int val1[N],val2[N];
 19 int dfn[N],low[N],dfs_clock,cnt;
 20 int belong[N];
 21 stack<int> st;
 22 bool vis[N];
 23 int ans,sum;
 24 void tarjan(int u, int fa)
 25 {
 26     bool flag = false;
 27     vis[u] = true;
 28     dfn[u] = low[u] = ++dfs_clock;
 29     st.push(u);
 30     for(int i=0; i<g1[u].size(); ++i)
 31     {
 32
 33         int v = g1[u][i];
 34         if(v==fa && !flag)
 35         {
 36             flag = true;
 37             continue;
 38         }
 39         if(!vis[v]) tarjan(v,u);
 40         low[u] = min(low[u],low[v]);
 41     }
 42     if(dfn[u]==low[u])
 43     {
 44         cnt++;
 45         int x;
 46         do
 47         {
 48             x= st.top();
 49             st.pop();
 50             belong[x] = cnt;
 51             val2[cnt] += val1[x];
 52         }while(u!=x);
 53     }
 54 }
 55
 56 void dfs(int u, int fa)
 57 {
 58     vis[u] = true;
 59     for(int i=0; i<g2[u].size(); ++i)
 60     {
 61         int v = g2[u][i];
 62         if(vis[v]) continue;
 63         dfs(v,u);
 64         val2[u] += val2[v];
 65     }
 66 }
 67 void dfs2(int u, int fa)
 68 {
 69     vis[u] = true;
 70     for(int i=0; i<g2[u].size(); ++i)
 71     {
 72         int v = g2[u][i];
 73         if(vis[v]) continue;
 74         ans = min(ans,abs(sum-2*val2[v]));
 75         dfs2(v,u);
 76     }
 77 }
 78 int main()
 79 {
 80     int n,m,i,u,v,j;
 81     while(scanf("%d%d",&n,&m)!=EOF)
 82     {
 83         for(i=0; i<=n; ++i)
 84         {
 85             g1[i].clear();
 86             g2[i].clear();
 87         }
 88         sum = 0;
 89         for(i=0; i<n; ++i)
 90         {
 91             scanf("%d",&val1[i]);
 92             sum += val1[i];
 93         }
 94         for(i=0; i<m; ++i)
 95         {
 96             scanf("%d%d",&u,&v);
 97             g1[u].push_back(v);
 98             g1[v].push_back(u);
 99         }
100         memset(vis,0,sizeof(vis));
101         memset(dfn,0,sizeof(dfn));
102         memset(low,0,sizeof(low));
103         memset(val2,0,sizeof(val2));
104         dfs_clock = 0;
105         cnt = 0;
106         tarjan(0,-1);
107         for(i=0; i<n; ++i)
108             for(j=0; j<g1[i].size(); ++j)
109             {
110                 int v = g1[i][j];
111                 if(belong[v] != belong[i])//建新图,虽然新建的图会有重边,但是不影响树形dp
112                 {
113                     g2[belong[i]].push_back(belong[v]);
114                     g2[belong[v]].push_back(belong[i]);
115                 }
116             }
117         if(cnt==1)//如果整个图是边连通的,那么不管删哪条边都不能使得图不连通
118         {
119             puts("impossible");
120             continue;
121         }
122         ans = INF;
123         memset(vis,0,sizeof(vis));
124         dfs(1,-1);
125         memset(vis,0,sizeof(vis));
126         dfs2(1,-1);
127         printf("%d\n",ans);
128     }
129     return 0;
130 }

时间: 2024-12-22 03:27:26

hdu2242(树形dp+tarjan+缩点)的相关文章

[树形dp][Tarjan][单调队列] Bzoj 1023 cactus仙人掌图

Description 如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌 图(cactus).所谓简单回路就是指在图上不重复经过任何一个顶点的回路. 举例来说,上面的第一个例子是一张仙人图,而第二个不是——注意到它有三条简单回路:(4,3,2,1,6 ,5,4).(7,8,9,10,2,3,7)以及(4,3,7,8,9,10,2,1,6,5,4),而(2,3)同时出现在前两 个的简单回路里.另外,第三张图也不是仙人图,因为它并不是连通图

考研路茫茫 (双连通 树形dp)

这道题就是模板的题加上一道很水的树形dp 感觉就先用 1,双连通缩点,如果只存在一个双连通分量,那么肯定是删除任何一个点,这个图还是连通的, 2,利用树形dp把缩点后连成一个图,然后用树形dp的一个dfs就算出答案了 #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <vector> #include <stack&g

[Bzoj 2427] [HAOI2010] 软件安装 tarjan缩点+树形DP

题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一 些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和最大). 但是现在有个问题:软件之间存在依赖关系,即软件i只有在安装了软件j(包括软件j的直接或间接依赖)的情况下才能正确工作(软件i依赖软件j).幸运的 是,一个软件最多依赖另外一个软件.如果一个软件不能正常工作,那么它能够发挥的作用为0. 我们现在知道了软件之间的依赖关系:软件i依赖软件Di.现在请你设计出

hdoj 2242 考研路茫茫——空调教室 【无向图求边双联通 缩点 + 树形dp】

考研路茫茫--空调教室 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2447    Accepted Submission(s): 721 Problem Description 众所周知,HDU的考研教室是没有空调的,于是就苦了不少不去图书馆的考研仔们.Lele也是其中一个.而某教室旁边又摆着两个未装上的空调,更是引起人们无限YY

HDU 2242 连通分量缩点+树形dp

题目大意是: 所有点在一个连通图上,希望去掉一条边得到两个连通图,且两个图上所有点的权值的差最小,如果没有割边,则输出impossible 这道题需要先利用tarjan算法将在同一连通分量中的点缩成一个点后,重新构建一幅图,然后利用新建的图进行树形dp解决问题 这道题目需要注意的是可能存在重边,那么子节点回到父节点有两条边及以上的话,就需要对子节点经过父节点的边进行low值更新 tarjan算法学习的网站个人感觉还不错https://www.byvoid.com/blog/scc-tarjan/

hdu2422考研路茫茫——空调教室 tarjan+树形dp

//给一个无向图,其每个顶点都有权值,求去掉一条边,将这个图分为两部分 //问这两部分的所有顶点和的绝对值的最小值 //用tarjan缩点 , 缩点后为一棵树 //然后用树形dp求出其最小的绝对值 // ans = min(ans , (int)(abs((double)(sum - 2*dp[v])))) ; //其中dp[u] 表示以u点为根节点的子树的学生数 #include<cstdio> #include<cstring> #include<iostream>

【BZOJ-1924】所驼门王的宝藏 Tarjan缩点(+拓扑排序) + 拓扑图DP

1924: [Sdoi2010]所驼门王的宝藏 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 787  Solved: 318[Submit][Status][Discuss] Description Input 第一行给出三个正整数 N, R, C. 以下 N 行,每行给出一扇传送门的信息,包含三个正整数xi, yi, Ti,表示该传送门设在位于第 xi行第yi列的藏宝宫室,类型为 Ti.Ti是一个1~3间的整数, 1表示可以传送到第 xi行任意

UVA 11324.The Largest Clique tarjan缩点+拓扑dp

题目链接:https://vjudge.net/problem/UVA-11324 题意:求一个有向图中结点数最大的结点集,使得该结点集中任意两个结点u和v满足:要目u可以到达v,要么v可以到达u(相互可达也可以). 思路:同一个强联通分量中满足结点集中任意两个结点u和v满足:要目u可以到达v,要么v可以到达u(相互可达也可以).把强联通分量收缩点后得到scc图,让每个scc结点的权值等于他的结点数,则求scc图上权最大的路径.拓扑dp,也可以直接bfs,但是要建立一个新的起点,连接所有入度为0

HDU5739 Fantasia 树形dp + 点双缩点

这个题当时打多校的时候有思路,但是代码能力差,没有写出来 事后看zimpha巨巨的题解,看了觉得基本差不多 核心思路:就是找出割点,然后变成森林,然后树形dp就可以搞了 关键就在重新构图上,缩完点以后,一个割点至少在两个点双里面,这个时候 把割点拿出来,分别和点双连边,也就是说,缩完的点双是不包含割点的,这个可以人为搞一下 (像有的点双里面只包含一个桥边,如果把割点拿出来,点双里面没有点了,这个时候把点双的权值积设为1就好) 然后说是树形dp,其实就是逆元搞一搞,这个很简单,树形dp只处理割点的