• HDOJ树形DP专题之考研路茫茫——空调教室


    题目链接

    题目大意:给定一个连通无向图,每个结点有一个值,现要断开图中某条边,使得原图变成两个连通子图,且要使两个子图的值的差最小。输出最小差,若无法完成,则输出"impossible”

    分析:要使断开某条边后,原图变成两个连通支,则断开的边一定是桥。对图进行DFS时,得到一颗树,图中有的而树中没有的边叫回边,回边一定不是桥。由此想到可用dfs将图转化为树来做,但树中的边不一定是原图中的桥,问题关键在于桥的判断。此题还需要注意的是可能有重边。

    View Code
      1 #include <stdio.h>
      2 #include <math.h>
      3 #include <string.h>
      4 #include <vector>
      5 #define N 10001
      6 #define M 40001
      7 #define INF 0x7fffffff
      8 #define MAX(a,b) ((a)>(b)?(a):(b))
      9 #define MIN(a,b) ((a)<(b)?(a):(b))
     10 using namespace std;
     11 vector<int> dep[N];
     12 int u[M],v[M],cnt[M],next[M],first[N],n,m;
     13 int num[N],sum[N];
     14 int p[N],d[N],dfn[N],low[N],dmax,id;
     15 char vis[N];
     16 void dfs(int a,int fa)
     17 {
     18   int e,b;
     19   d[a]=(fa==-1?0:d[fa]+1);
     20   dmax=MAX(dmax,d[a]);
     21   dep[d[a]].push_back(a);
     22   for(e=first[a];e>=0;e=next[e])
     23   {
     24     b=v[e];
     25     if(b==fa) continue;
     26     if(vis[b])  low[a]=MIN(low[a],dfn[b]);
     27     else
     28     {
     29       vis[b]=1;
     30       dfn[b]=low[b]=++id;
     31       dfs(b,p[b]=a);
     32       low[a]=MIN(low[a],low[b]);
     33     }
     34   }
     35 }
     36 void dp()
     37 {
     38   int e,b,i,j;
     39   memset(sum,0,sizeof(sum));
     40   for(i=dmax;i>=0;i--)
     41   {
     42     for(j=0;j<dep[i].size();j++)
     43     {
     44       b=dep[i][j];
     45       sum[b]+=num[b];
     46       if(i) sum[p[b]]+=sum[b];
     47     }
     48   }
     49 }
     50 void addEdge(int a,int b,int e)
     51 {
     52   u[e]=a,v[e]=b;
     53   cnt[e]=1;
     54   next[e]=first[a];
     55   first[a]=e;
     56 }
     57 int findEdge(int a,int b)
     58 {
     59   int e;
     60   for(e=first[a];e>=0;e=next[e])
     61   {
     62     if(v[e]==b)
     63     {
     64       cnt[e]++;
     65       return 1;
     66     }
     67   }
     68   return 0;
     69 }
     70 int main()
     71 {
     72   int i,e,a,b,ans;
     73   while(~scanf("%d%d",&n,&m))
     74   {
     75     for(i=0;i<n;i++)  scanf("%d",&num[i]);
     76     memset(u,-1,sizeof(u));
     77     memset(v,-1,sizeof(v));
     78     memset(first,-1,sizeof(first));
     79     memset(next,-1,sizeof(next));
     80     memset(cnt,0,sizeof(cnt));
     81     for(e=0;e<m;e++)
     82     {
     83       scanf("%d%d",&a,&b);
     84       if(findEdge(a,b)+findEdge(b,a)==0)
     85       {
     86         addEdge(a,b,2*e);
     87         addEdge(b,a,2*e+1);
     88       }
     89     }
     90     memset(vis,0,sizeof(vis));
     91     vis[0]=1;
     92     dfn[0]=low[0]=id=1;
     93     p[0]=-1;
     94     dmax=0;
     95     for(i=0;i<n;i++)  dep[i].clear();
     96     dfs(0,-1);
     97     dp();
     98     ans=INF;
     99     for(e=0;e<m;e++)
    100     {
    101       if(cnt[2*e]>1)  continue;
    102       a=u[2*e],b=v[2*e];
    103       if(p[a]==b&&low[a]>dfn[b]) ans=MIN(ans,abs(2*sum[a]-sum[0]));
    104       else if(p[b]==a&&low[b]>dfn[a])  ans=MIN(ans,abs(2*sum[b]-sum[0]));
    105     }
    106     if(ans==INF)  puts("impossible");
    107     else  printf("%d\n",ans);
    108   }
    109   return 0;
    110 }
  • 相关阅读:
    .NET 高效开发之不可错过的实用工具(第一的当然是ReSharper插件)
    灵活运用 SQL SERVER FOR XML PATH 转
    Python 3.X 要使用urllib.request 来抓取网络资源。转
    22-1 拖拽与烟花案例
    21、bootstrap框架
    20、promise与ajax jsonp
    18、MySQL
    19、AJAX
    17、php
    16-1 ECMA5与ECMA6的函数定义
  • 原文地址:https://www.cnblogs.com/algorithms/p/2479043.html
Copyright © 2020-2023  润新知