zoukankan      html  css  js  c++  java
  • HDU 2242 考研路茫茫—空调教室 (边双连通+树形DP)

    <题目链接>

    题目大意:

    给定一个连通图,每个点有点权,现在需要删除一条边,使得整张图分成两个连通块,问你删除这条边后,两联通块点权值和差值最小是多少。

    解题分析:

    删除一条边,使原连通图分成两个连通分量,所以删除的那条边必然是桥。为了得到所有的桥,我们对原图进行边双连通图缩点。然后对缩点后的新图,跑一遍树形DP,得到所有桥两端点权和的最小差值。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define clr(a,b) memset(a,b,sizeof(a))
     5 const int N = 1e4+5, M = 2e4+5;
     6 struct Edge{
     7     int from,to,nxt;
     8 }edge[M<<1],edge1[M<<1];
     9 
    10 int n,m,cnt,cnt1,sum,ans,dcc,tot,top;
    11 int head[N],head1[N],instk[N],bel[N],dfn[N],low[N],val[N],val1[N],cost[N],stk[N];
    12 
    13 void init(){
    14     cnt=tot=sum=dcc=cnt1=0;ans=1e9;
    15     clr(dfn,0);clr(low,0);clr(val,0);clr(head,-1);clr(head1,-1);
    16     clr(instk,0);clr(cost,0);
    17 }
    18 void addedge(int u,int v){ edge[cnt].from=u;edge[cnt].to=v;edge[cnt].nxt=head[u];head[u]=cnt++; }
    19 void addedge1(int u,int v){ edge1[cnt1].from=u;edge1[cnt1].to=v;edge1[cnt1].nxt=head1[u];head1[u]=cnt1++; }
    20 
    21 void Tarjan(int u,int fa){    //Tarjan找边双连通分量并进行缩点
    22     dfn[u]=low[u]=++tot;
    23     instk[u]=1;stk[++top]=u;
    24     int flag=0;
    25        for(int i=head[u];~i;i=edge[i].nxt){
    26            int v=edge[i].to;
    27            if(v==fa && !flag){ flag=1;continue; }    //跳过搜索树上的边,这种写法能够处理重边的情况
    28            if(!dfn[v]){
    29                Tarjan(v,u);
    30                low[u]=min(low[u],low[v]);
    31            }else if(instk[v])low[u]=min(low[u],dfn[v]);
    32        }
    33     if(dfn[u]==low[u]){
    34         ++dcc;
    35         while(true){
    36             int v=stk[top--];
    37             bel[v]=dcc;
    38             val[dcc]+=val1[v];
    39             if(v==u)break;
    40         }
    41     }
    42 }
    43 void dfs(int u,int pre){    //树形DP得到桥两边差值的最小值
    44     cost[u]=val[u];
    45     for(int i=head1[u];~i;i=edge1[i].nxt){
    46         int v=edge1[i].to;
    47         if(v==pre)continue;
    48         dfs(v,u);
    49         cost[u]+=cost[v];
    50     }
    51     ans=min(ans,abs(sum-2*cost[u]));
    52 }
    53 int main(){
    54     while(scanf("%d%d",&n,&m)!=EOF){
    55         init();
    56         for(int i=0;i<n;i++)
    57             scanf("%d",&val1[i]),sum+=val1[i];
    58         for(int i=1;i<=m;i++){
    59             int u,v;scanf("%d%d",&u,&v);
    60             addedge(u,v),addedge(v,u);
    61         }
    62         Tarjan(0,0);
    63         if( dcc==1 ) { puts("impossible");continue; }   //如果该图是边双连通图,说明没有桥
    64         for(int i=0;i<cnt;i++){
    65             int u,v;u=edge[i].from;v=edge[i].to;
    66             if(bel[u]!=bel[v])addedge1(bel[u],bel[v]);     //建立单向边
    67         }
    68         dfs(1,-1);
    69         printf("%d
    ",ans);
    70     }
    71 }

    2019-03-02

  • 相关阅读:
    char *s 和char s[]的区别
    Loadrunner时间函数、用时间生成订单编号例子
    loadrunner获取毫秒及字符串替换实现
    关联的特殊应用
    LR中的时间戳函数web_save_timestamp_param
    使用 If-Then-Else 逻辑进行分支
    ArcGIS中国工具3.2新功能
    运行模型,COM错误,解决问题步骤
    arcgis python 更新日期为随机数
    使用LAS数据集创建DEM和DSM
  • 原文地址:https://www.cnblogs.com/00isok/p/10459304.html
Copyright © 2011-2022 走看看