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 }

 

你可能感兴趣的:(dp)