hdu 2242 无向图/求用桥一分为二后使俩个bcc点权值和之差最小并输出 /缩点+2次新图dfs

题意如标题所述,

先无向图缩点,统计出每个bcc权,建新图,然后一遍dfs生成树,标记出每个点(新图)以及其子孙的权值之和。这样之后就可以dfs2来枚举边(原图的桥),更新最小即可。

调试了半天!原来是建老图时候链式前向星和新图的vector<vector< int>>俩种存图搞乱了!!!不可原谅!哎!愚蠢!愚不可及!提交后1A。

后来百度之后,发现说是用树形dp,看了代码解法,竟然和我的是一样的算法。。原来这种算法可以叫树形dp。。。的确有点dp味道。。不过感觉不太浓。。

以后多个图,多种储存方式要分清!e[i][j]!!!e[u][i]\e[j][1]。。。

#include<iostream>
#include<cstdio>
#include<stack>
#include<vector>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxv=10010,maxe=50000;
int head[maxv];int nume=0;int e[maxe][2];
void inline adde(int i,int j)
{
    e[nume][0]=j;e[nume][1]=head[i];head[i]=nume++;
    e[nume][0]=i;e[nume][1]=head[j];head[j]=nume++;
}
int dfn[maxv];int low[maxv];int vis[maxv];int bcc[maxv];int ins[maxv];stack<int>sta;
int times=0; int numb=0; int vise[maxe];
int wi[maxv]; int sumwi[maxv];
void tarjan(int u)
{
     dfn[u]=low[u]=times++;
     ins[u]=1;
     sta.push(u);
     for(int i=head[u];i!=-1;i=e[i][1])
     {
         if(vise[i])continue;
         int v=e[i][0];
         if(!vis[v])
         {
             vis[v]=1;
             vise[i]=vise[i^1]=1;
             tarjan(v);
             if(low[v]<low[u])low[u]=low[v];
         }
         else if(ins[v]&&dfn[v]<low[u])
            low[u]=dfn[v];
     }
     if(low[u]==dfn[u])
     {
         numb++;
         int cur;
         do{
             cur=sta.top();
             sta.pop();
             ins[cur]=0;
             bcc[cur]=numb;
             sumwi[numb]+=wi[cur];
         }while(cur!=u);
     }
}
vector<vector<int> >e2(maxv+1);
int n,m; int mindis=inf;
int getabs(int x)
{
    return x<0?-x:x;
}
void init()
{
    numb=times=nume=0;mindis=inf;
    memset(vise,0,sizeof(vise));
    for(int i=0;i<maxv;i++)
      {
         sumwi[i]=wi[i]=bcc[i]=ins[i]=dfn[i]=low[i]=vis[i]=0;
         e2[i].clear(); head[i]=-1;
      }
}
int dfs(int u)             //获得sumwi【i】:子孙包括自己的权值和
{
    for(int i=0;i<e2[u].size();i++)
    {
        int v=e2[u][i];
        if(!vis[v])
        {
            vis[v]=1;
            sumwi[u]+=dfs(v);
        }
    }
    return sumwi[u];
}
void dfs2(int u)
{
   for(int i=0;i<e2[u].size();i++)
    {
        int v=e2[u][i];
        if(!vis[v])
        {
            if(getabs(sumwi[1]-sumwi[v]-sumwi[v])<mindis)
            {
                mindis=getabs(sumwi[1]-sumwi[v]-sumwi[v]);
            }
            vis[v]=1;
            dfs2(v);
        }
    }
}
void solve()
{
    vis[0]=1;
    tarjan(0);
   if(numb==1)
   {
       printf("impossible\n");
       return ;
   }
   memset(vise,0,sizeof(vise));
   for(int i=0;i<n;i++)
     for(int j=head[i];j!=-1;j=e[j][1])
        if(bcc[i]!=bcc[e[j][0]]&&vise[j]==0)
            {
                e2[bcc[i]].push_back(bcc[e[j][0]]);
                e2[bcc[e[j][0]]].push_back(bcc[i]);
                vise[j]=vise[j^1]=1;
            }
    memset(vis,0,sizeof(vis));
    vis[1]=1;
    dfs(1);
    memset(vis,0,sizeof(vis));
    vis[1]=1;
    dfs2(1);
   printf("%d\n",mindis);
}
void readin()
{
    for(int i=0;i<n;i++)
        scanf("%d",&wi[i]);
    int aa,bb;
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&aa,&bb);
        adde(aa,bb);
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        readin();
        solve();
    }
    return 0;
}

hdu 2242 无向图/求用桥一分为二后使俩个bcc点权值和之差最小并输出 /缩点+2次新图dfs,布布扣,bubuko.com

时间: 2024-10-27 08:14:45

hdu 2242 无向图/求用桥一分为二后使俩个bcc点权值和之差最小并输出 /缩点+2次新图dfs的相关文章

HDU 4738 无向图求桥

使用tarjan算法求桥,模板题,但是... 1.有重边 2.不一定连通 3.没有人守桥至少要派一个人去 http://acm.hdu.edu.cn/showproblem.php?pid=4738 这种题挺好的,可以锻炼人的耐性和心理承受能力... #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <vector> us

HDU 3849 无向图求桥

By Recognizing These Guys, We Find Social Networks Useful Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 125536/65536 K (Java/Others)Total Submission(s): 2563    Accepted Submission(s): 671 Problem Description Social Network is popular these

HDU 4738——Caocao&#39;s Bridges——————【求割边/桥的最小权值】

Caocao's Bridges Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4738 Description Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi. But he wouldn't give up. Caocao's army st

朱、刘算法:求最小树形图权值个人理解+个人详解【最小树形图模板】

什么是最小树形图?相信大家如果会过来看这篇文章,想必也应该对最小生成树有所了解的,最小生成树求的是无向图的一颗生成树的最小权值.我们的最小树形图就是来解决一个有向图的一颗生成树的最小权值,对于度娘来说,最小树形图是这样定义的:最小树形图,就是给有向带权图中指定一个特殊的点root,求一棵以root为根的有向生成树T,并且T中所有边的总权值最小. 通解最小树形图的一种算法是是1965年朱永津和刘振宏提出的复杂度为O(VE)的算法:朱.刘算法. 今天我们就来浅谈一下最小树形图的问题. 大题上完整的朱

hdu4612 无向图中任意添加一条边后使桥的数量最少 / 无向图缩点+求树的直径

题意如上,含有重边(重边的话,俩个点就可以构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选任意起点U,进行bfs,到达最远的一个点v(level最深)该点必然是树的直径的一个端点,,再从该点出发,bfs,到最深的一点,该点深度就是直径.(证明:先假设u,是直径上一点,S,T是直径的端点,设v!=t,则有(V,U)+(U,S)>(T,U)+(U,S),矛盾,故t=v:若u不是直径上一点,设u到直径上的一点为x,同理易证. 最后 缩

HDU 4738 --Caocao&#39;s Bridges 【无向图边双联通 &amp;&amp; 求权值最小的桥 &amp;&amp; 模板】

Caocao's Bridges Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2641    Accepted Submission(s): 855 Problem Description Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi. B

hdu4612 无向图中随意加入一条边后使桥的数量最少 / 无向图缩点+求树的直径

题意如上,含有重边(重边的话,俩个点就能够构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选随意起点U,进行bfs,到达最远的一个点v(level最深)该点必定是树的直径的一个端点,,再从该点出发,bfs,到最深的一点.该点深度就是直径. (证明:先如果u.是直径上一点,S,T是直径的端点.设v!=t,则有(V,U)+(U,S)>(T,U)+(U,S),矛盾,故t=v:若u不是直径上一点.设u到直径上的一点为x.同理易证. 最后

无向图求割顶与桥

无向图求割顶与桥 对于无向图G,如果删除某个点u后,连通分量数目增加,称u为图的关节点或割顶.对于连通图,割顶就是删除之后使图不再连通的点.如果删除边(u,v)一条边,就可以让连通图变成不连通的,那么边(u,v)是桥. 具体的概念和定义比较多,在刘汝佳<<训练指南>>P312-314页都有详细的介绍. 下面来写求无向图割顶和桥的DFS函数.我们令pre[i]表示第一次访问i点的时间戳,令low[i]表示i节点及其后代所能连回(通过反向边)的最早祖先的pre值. 下面的dfs函数返回

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