题目大意是:

所有点在一个连通图上,希望去掉一条边得到两个连通图,且两个图上所有点的权值的差最小,如果没有割边,则输出impossible

这道题需要先利用tarjan算法将在同一连通分量中的点缩成一个点后,重新构建一幅图,然后利用新建的图进行树形dp解决问题

这道题目需要注意的是可能存在重边,那么子节点回到父节点有两条边及以上的话,就需要对子节点经过父节点的边进行low值更新

tarjan算法学习的网站个人感觉还不错https://www.byvoid.com/blog/scc-tarjan/

 /*
找割边是否存在
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <stack>
using namespace std; typedef long long ll;
const int N = ;
const int INF = ; int first[N] , k , k_scc , val[N] , val_scc[N] , sum[N] , all ;
int scc[N] , num_of_scc , dfs_clock , dfn[N] , low[N];
stack<int> s; struct Edge{
int x , y , next ;
bool flag;
}e[N<<] , e_scc[N<<]; int my_abs(int x)
{
return x>=?x:-x;
} void add_edge(int x , int y)
{
e[k].x = x , e[k].y = y , e[k].next = first[x];
first[x] = k++;
} void add_edge_scc(int x , int y)
{
e_scc[k_scc].x = x , e_scc[k_scc].y = y , e_scc[k_scc].next = first[x] , e_scc[k_scc].flag = false;
first[x] = k_scc++;
} void tarjan(int u , int fa)
{
dfn[u] = low[u] = ++dfs_clock;
s.push(u);
int flag = ; //用来解决重边情况
for(int i=first[u] ; i!=- ; i=e[i].next){
int v = e[i].y;
/*
因为第一次遇到父节点的边,表示是一开始下来的边,这个是不允许访问的,
但是如果遇到2次及以上,说明u v之间不止一条边,访问到第二次之后的边是允许
low[u]通过这个重边得到dfn[v]比较下的较小值进行更新
*/
if(v == fa && flag){
flag = ;
continue;
}
if(!dfn[v]){
tarjan(v,u);
low[u] = min(low[u] , low[v]);
}
else if(!scc[v])
low[u] = min(low[u] , dfn[v]);
}
if(low[u] == dfn[u]){
num_of_scc++;
while(true){
int x = s.top();
s.pop();
scc[x] = num_of_scc;
val_scc[num_of_scc] += val[x];//得到新构建图上的点的权值
if(x == u) break;
}
}
} void dfs(int u , int fa)
{
sum[u] = val_scc[u];
for(int i=first[u] ; i!=- ; i=e_scc[i].next){
int v = e_scc[i].y;
if(v == fa) continue;
e_scc[i].flag = true;
dfs(v , u);
sum[u]+=sum[v];
}
} int main()
{
// freopen("a.in" , "r" , stdin);
int n , m , x , y;
while(scanf("%d%d" , &n , &m) == ){
memset(first , - , sizeof(first));
k= , all = ;
for(int i= ; i<n ; i++)
{
scanf("%d" , val+i);
all += val[i];
} for(int i= ; i<m ; i++){
scanf("%d%d" , &x , &y);
add_edge(x , y);
add_edge(y , x);
} //强连通分量缩点
dfs_clock = , num_of_scc = ;
memset(dfn , ,sizeof(dfn));
memset(scc , , sizeof(scc));
memset(val_scc , , sizeof(val_scc));
tarjan( , -); if(num_of_scc == ){
puts("impossible");
continue;
} //重新构建一个以连通分量缩点后的树形图
memset(first , - , sizeof(first));
k_scc = ;
for(int i= ; i<k ; i++){
if(scc[e[i].x] == scc[e[i].y]) continue;
add_edge_scc(scc[e[i].x] , scc[e[i].y]);
}
dfs( , -); int minn = INF;
for(int i= ; i<k_scc ; i++){
if(!e_scc[i].flag) continue;
minn = min(minn , my_abs(all - sum[e_scc[i].y] - sum[e_scc[i].y]) );
}
printf("%d\n" , minn);
}
return ;
}

最新文章

  1. hellocharts的折线图与柱状图的结合之ComboLineColumnChartView
  2. 有关DOM
  3. 初刷LeetCode的感受
  4. LocalBroadcastManager 的实现原理,Handler还是 Binder?
  5. [java]wordcount程序
  6. 【读书笔记】iOS-对象初始化
  7. .Net 三款工作流引擎比较:WWF、netBPM 和 ccflow
  8. Servlet应用的运行流程
  9. Altium Designer 14(或者其他版本)里更改PCB板(图纸)大小
  10. 智能电视TV开发---如何实现程序省电
  11. [Windwos Phone] 实作地图缩放 MapAnimationKind 属性效果
  12. sql性能
  13. VS2013中使用QT插件后每次重新编译问题
  14. C语言代码训练(一)
  15. Java 的概述
  16. LAN、WAN、WLAN、WiFi之间的区别
  17. loadrunner断言多结果返回
  18. Linux-网络管理
  19. 【Thread】CountdownEvent任务并行[z]
  20. 基于Jenkins的持续集成CI

热门文章

  1. bzoj 1598: [Usaco2008 Mar]牛跑步【A*K短路】
  2. 慕课网4-6 编程练习:jQuery后排兄弟选择器
  3. 微信小程序-wepy-组件模板重复渲染
  4. 数据返回(数据共享,即从后端返回到前端调用,四种(requesst、ModelAndView、Model、Map))
  5. nginx connect failed (110- Connection timed out) 问题排查
  6. 预采订单管理接收来源App数据
  7. eclipse中folder、source folder和package的区别
  8. Python批量生成用户名
  9. C# 调用Mysql 带参数存储过程
  10. dede手机访问网站跳转到手机端模板