hdu 2242 考研路茫茫——空调教室

双联通缩点+树形DP~~

前些天做树形DP的时候就发现这道题了,那时候没学双联通不知道怎么样缩点,这两天又把tarjan学了一下,先学习用tarjan解决强联通,之后感觉用tarjan解决双联通

与强联通有类似之处,今天早上终于把双联通缩点学会了。。^_^。。。

题目大意:给一个教室群,问能不能把这些教室群分成两部分,并且使两部分之间的权值差最小(每一个教室都有一定的权值);

思路:先用双联通进行缩点,因为那些双向连通的教室肯定是分不开的,所以要把它们缩成一个点。

之后再重新建图,用树形DP一下求最小差值!

需要注意一点这道题的数据包含重边,需要考虑!!

代码:

View Code
 1 # include<stdio.h>
2 # include<string.h>
3 # include<stack>
4 using namespace std;
5 # define N 10005
6 # define M 20005
7 struct node{
8 int from,to,next;
9 }edge[2*M],edge1[2*M];
10 int head[N],tol,n,m,cnt,dfn[N],low[N],visit[N],Belong[N],tol1,head1[N],val[N],val1[N],SUM,Min,count;
11 stack<int>S;
12 void add(int a,int b)
13 {
14 edge[tol].from=a;edge[tol].to=b;edge[tol].next=head[a];head[a]=tol++;
15 }
16 void add1(int a,int b)
17 {
18 edge1[tol1].from=a;edge1[tol1].to=b;edge1[tol1].next=head1[a];head1[a]=tol1++;
19 }
20 int min(int a,int b)
21 {
22 return a<b?a:b;
23 }
24 void tarjan(int u,int father)//tarjan找双连通分量并进行缩点
25 {
26 int j,v,flag;
27 dfn[u]=low[u]=cnt++;
28 visit[u]=1;
29 S.push(u);
30 flag=0;
31 for(j=head[u];j!=-1;j=edge[j].next)
32 {
33 v=edge[j].to;
34 if(v==father && !flag) {flag=1;continue;}//考虑重边的情况,相当重要!
35 if(!visit[v]) tarjan(v,u);
36 low[u]=min(low[u],low[v]);
37 }
38 if(dfn[u]==low[u])
39 {
40 count++;
41 do{
42 v=S.top();
43 S.pop();
44 Belong[v]=count;
45 val[count]+=val1[v];
46 }while(v!=u);
47 }//用栈的好处在于使双联通分量的标号连续,如果直接用low[u]来存u的双联通分量,双联通分量的标号不连续,之后再建图的时候不方便
48 }
49 int dfs(int u,int father)//树形DP求解最小差值
50 {
51 int j,v,sum;
52 sum=val[u];
53 for(j=head1[u];j!=-1;j=edge1[j].next)
54 {
55 v=edge1[j].to;
56 if(v==father) continue;
57 sum+=dfs(v,u);
58 }
59 Min=min(Min,abs(SUM-2*sum));
60 return sum;
61 }
62 int main()
63 {
64 int i,a,b;
65 while(scanf("%d%d",&n,&m)!=EOF)
66 {
67 memset(head,-1,sizeof(head));
68 tol=cnt=0;
69 SUM=0;
70 for(i=0;i<n;i++)
71 {
72 scanf("%d",&val1[i]);
73 SUM+=val1[i];
74 }
75 for(i=1;i<=m;i++)
76 {
77 scanf("%d%d",&a,&b);
78 add(a,b);
79 add(b,a);
80 }
81 memset(visit,0,sizeof(visit));
82 memset(val,0,sizeof(val));
83 count=0;//存双联通分量的个数
84 tarjan(0,0);
85 if(count==1) {printf("impossible\n");continue;}
86 tol1=0;
87 memset(head1,-1,sizeof(head1));
88 for(i=0;i<tol;i++)
89 {
90 a=edge[i].from;
91 b=edge[i].to;
92 if(Belong[a]!=Belong[b]) add1(Belong[a],Belong[b]);
93 }
94 Min=0xfffffff;
95 dfs(1,0);
96 printf("%d\n",Min);
97 }
98 return 0;
99 }

你可能感兴趣的:(HDU)