树形DP小结:
1:n个点,n-1条边;
2:无环,根结点可由子结点推出;
3:一般的状态都是以某一个结点为根的子树代表什么,
然后通过递归,由一个一个子结点推出根结点状态;
递推关系:Dp[i][j]=max(dp[i][j],dp[i][k]+dp[son[i][j-k]);
说明递推的含义,首先dp[i][j]的第一个值肯定从dp[son[i]][k]来,当换另一个son2[i],dp[i][j]就是由俩个son推出,其他son同理;
4:对于一棵树,可以随意选一个点为根,开一个vis[]数组,记录该结点是否访问过;
http://acm.hdu.edu.cn/showproblem.php?pid=1520
最裸的树形DP, 定义dp[i][0]表示以i为根的子树不选i能邀请到的最大值;
Dp[i][1]表示以i为根的子树选i能邀请到的最大值;
状态转移:dp[i][0]+=max(dp[son][0],dp[son][1]); dp[i][1]+=dp[son][0];
注意每个点的值有正有负;
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 const int MAXN=6010; 10 int dp[MAXN][2]; 11 const int INF=1000000; 12 vector <int > g[MAXN]; 13 int c[MAXN]; 14 int n; 15 int v[MAXN]; 16 void TREEDP(int root) 17 { 18 int d=g[root].size(); 19 if (d==0) { 20 dp[root][1]=c[root]; 21 dp[root][0]=0; 22 return ; 23 } 24 for (int i=0;i<d;i++) 25 { 26 int c=g[root][i]; 27 TREEDP(c); 28 } 29 30 dp[root][1]=c[root]; 31 for (int i=0;i<d;i++) 32 { 33 int c=g[root][i]; 34 if (dp[c][0]>0) 35 dp[root][1]+=dp[c][0]; 36 } 37 dp[root][0]=-INF; 38 for (int i=0;i<d;i++) 39 { 40 int c=g[root][i]; 41 int t=max(dp[c][1],dp[c][0]); 42 if (t>0 && dp[root][0]<0) 43 { 44 dp[root][0]=t; 45 } else if (t<0 && dp[root][0]<0) 46 { 47 if (dp[root][0]<t) dp[root][0]=t; 48 } else if (t>0 && dp[root][0]>=0) 49 { 50 dp[root][0]+=t; 51 } 52 } 53 } 54 int main() 55 { 56 // freopen("D:\in.txt","r",stdin); 57 while (~scanf("%d",&n)) 58 { 59 for (int i=1;i<=n;i++) 60 { 61 scanf("%d",&c[i]); 62 g[i].clear(); 63 } 64 int u,v; 65 bool vis[MAXN]; 66 memset(vis,0,sizeof(vis)); 67 while (~scanf("%d%d",&u,&v)) 68 { 69 if (u==0 && v==0) break; 70 g[v].push_back(u); 71 vis[u]=1; 72 } 73 memset(dp,0,sizeof(dp)); 74 75 for (int i=1;i<=n;i++) 76 { 77 if (vis[i]==0) 78 { 79 TREEDP(i); 80 cout<<max(dp[i][0],dp[i][1])<<endl; 81 break; 82 } 83 } 84 85 86 } 87 88 return 0; 89 }
http://acm.hdu.edu.cn/showproblem.php?pid=2412
和上一题基本一样,但还要询问方案是否唯一;加一个数组记录当前状态是否唯一如果不唯一,当根结点的状态有它推出时,根结点的状态也就不唯一
//程序统一输出的方式,不要cout和printf混用,俩着输出性质不一样;
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<iostream> 5 #include<algorithm> 6 #include<map> 7 #include<vector> 8 #include<string> 9 using namespace std; 10 const int MAXN=210; 11 map<string,int > mp; 12 int sz; 13 vector <int >g[MAXN]; 14 int dp[MAXN][2]; 15 int dug[MAXN][2]; 16 int vis[MAXN]; 17 int n; 18 void init() 19 { 20 sz=0; 21 mp.clear(); 22 for (int i=0;i<n;i++) g[i].clear(); 23 memset(vis,0,sizeof(vis)); 24 } 25 void TREEDP(int rt) 26 { 27 if (vis[rt]) return ; 28 vis[rt]=1; 29 int d=g[rt].size(); 30 if (d==0) 31 { 32 dp[rt][0]=0; 33 dp[rt][1]=1; 34 dug[rt][0]=1; 35 dug[rt][1]=1; 36 return; 37 } 38 dp[rt][0]=dp[rt][1]=0; 39 dug[rt][0]=dug[rt][1]=1; 40 for (int i=0;i<d;i++) 41 { 42 int c=g[rt][i]; 43 if (!vis[c]) 44 { 45 TREEDP(c); 46 } 47 dp[rt][1]+=dp[c][0]; 48 if (dug[c][0]==0) dug[rt][1]=0; 49 dp[rt][0]+=max(dp[c][1],dp[c][0]); 50 if (dp[c][1]>dp[c][0] && dug[c][1]==0) 51 { 52 dug[rt][0]=0; 53 } else 54 if (dp[c][1]<dp[c][0] && dug[c][0]==0) 55 { 56 dug[rt][0]=0; 57 } else if (dp[c][1]==dp[c][0]) dug[rt][0]=0; 58 } 59 dp[rt][1]+=1; 60 61 62 } 63 int mp_find(string s) 64 { 65 if (mp.find(s)==mp.end()) 66 { 67 mp[s]=sz++; 68 } 69 return mp[s]; 70 } 71 int main() 72 { 73 //freopen("D:\in.txt","r",stdin); 74 string s,s1,s2; 75 while (cin>>n) 76 { 77 if (n==0) break; 78 init(); 79 cin>>s; 80 mp_find(s); 81 for (int i=0;i<n-1;i++) 82 { 83 cin>>s1>>s2; 84 int u=mp_find(s1); 85 int v=mp_find(s2); 86 g[v].push_back(u); 87 } 88 89 TREEDP(0); 90 91 if (dp[0][1]>dp[0][0]) 92 { 93 if(dug[0][1]) cout<<dp[0][1]<<" Yes"<<endl;//printf("%d Yes\n",dp[0][1]); 94 else cout<<dp[0][1]<<" No"<<endl;//printf("%d No\n",dp[0][1]); 95 } else if (dp[0][1]<dp[0][0]) 96 { 97 if(dug[0][0])cout<<dp[0][0]<<" Yes"<<endl;// printf("%d Yes\n",dp[0][0]); 98 else cout<<dp[0][0]<<" No"<<endl;//printf("%d No\n",dp[0][0]); 99 } else 100 { 101 cout<<dp[0][1]<<" No"<<endl;//printf("%d No\n",dp[0][1]); 102 103 } 104 105 106 } 107 108 109 return 0; 110 }
http://acm.hdu.edu.cn/showproblem.php?pid=3899
很裸的树形DP,先一遍dfs,统计出以每个结点为根的子树包含的队伍,和该子树以该子树跟为聚集地所走的路径,这样就算出了以根结点为聚集地需要的总路程;
再一遍 dfs,由总根结点推到子结点,记录下最小值。
//对于数据大的,但有感觉没有超,还是果断用long long ,有可能中间计算超了;
//该题用dfs递归会爆栈,要手写stack,或用C++交可以用爆栈外挂,
#pragma comment(linker, "/STACK:1024000000,1024000000")
1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<cstdlib> 7 #include<cmath> 8 #include<vector> 9 using namespace std; 10 const int N=100100; 11 typedef __int64 ll; 12 ll dp[N]; 13 ll dug[N]; 14 int n; 15 ll c[N],vis[N]; 16 ll ans; 17 struct node 18 { 19 int v,w; 20 }; 21 vector <node> g[N]; 22 void TREEDP(int rt) 23 { 24 vis[rt]=1; 25 int d=g[rt].size(); 26 if (d==0) 27 { 28 dp[rt]=c[rt]; 29 dug[rt]=0; 30 return; 31 } 32 dp[rt]=c[rt]; 33 dug[rt]=0; 34 for (int i=0;i<d;i++) 35 { 36 int c=g[rt][i].v; 37 int w=g[rt][i].w; 38 if (vis[c]) continue; 39 TREEDP(c); 40 dp[rt]+=dp[c]; 41 dug[rt]+=dp[c]*w+dug[c]; 42 } 43 } 44 void init() 45 { 46 memset(dp,0,sizeof(dp)); 47 for (int i=1;i<=n;i++) g[i].clear(); 48 memset(vis,0,sizeof(vis)); 49 memset(dug,0,sizeof(dug)); 50 } 51 void solve(int rt) 52 { 53 vis[rt]=1; 54 int d=g[rt].size(); 55 for (int i=0;i<d;i++) 56 { 57 int c=g[rt][i].v; 58 if (vis[c]) continue; 59 int w=g[rt][i].w; 60 ll t1=dp[c],t2=dug[c]; 61 ll t3=dp[rt],t4=dug[rt]; 62 63 dp[c]=t3; 64 dp[rt]=t3-t1; 65 dug[rt]=t4-t1*w-t2; 66 dug[c]=t4-w*t1+(t3-t1)*w; 67 ans=min(dug[c],ans); 68 solve(c); 69 dp[c]=t1;dug[c]=t2; 70 dp[rt]=t3;dug[rt]=t4; 71 } 72 vis[rt]=0; 73 74 } 75 int main() 76 { 77 //freopen("D:\in.txt","r",stdin); 78 while (~scanf("%d",&n)) 79 { 80 for (int i=1;i<=n;i++) 81 { 82 scanf("%I64d",&c[i]); 83 } 84 init(); 85 for (int i=0;i<n-1;i++) 86 { 87 int u,v,w; 88 scanf("%d%d%d",&u,&v,&w); 89 node t1={v,w}; 90 g[u].push_back(t1); 91 node t2={u,w}; 92 g[v].push_back(t2); 93 } 94 TREEDP(1); 95 ans=dug[1]; 96 //cout<<ans<<endl; 97 memset(vis,0,sizeof(vis)); 98 solve(1); 99 printf("%I64d\n",ans); 100 101 } 102 103 return 0; 104 }
http://acm.hdu.edu.cn/showproblem.php?pid=2196
求树上离一个点最远的距离;我是先一遍dfs记录下以该点为根的子树的子结点到根的最远距离,然后转移总根结点,求出每个结点的ans;同上类似;
1 2 #include<cstdio> 3 #include<iostream> 4 #include<cstring> 5 #include<algorithm> 6 #include<cstdlib> 7 #include<cmath> 8 #include<vector> 9 using namespace std; 10 typedef long long ll; 11 const int N=10010; 12 ll dp[N]; 13 struct node 14 { 15 int v,w; 16 }; 17 vector<node> g[N]; 18 int vis[N]; 19 ll c[N]; 20 int n; 21 void init() 22 { 23 for (int i=1;i<=n;i++) 24 g[i].clear(); 25 memset(dp,0,sizeof(dp)); 26 memset(vis,0,sizeof(vis)); 27 } 28 void TREEDP(int rt) 29 { 30 vis[rt]=1; 31 int d=g[rt].size(); 32 if (d==0) 33 { 34 dp[rt]=0; 35 return; 36 } 37 for (int i=0;i<d;i++) 38 { 39 ll v=g[rt][i].v; 40 ll w=g[rt][i].w; 41 if (vis[v]) continue; 42 TREEDP(v); 43 dp[rt]=max(dp[rt],dp[v]+w); 44 } 45 46 } 47 ll find(int rt,int x) 48 { 49 ll t=0; 50 int d=g[rt].size(); 51 for (int i=0;i<d;i++) 52 { 53 int v=g[rt][i].v; 54 int w=g[rt][i].w; 55 if(x==v) continue; 56 t=max(t,dp[v]+w); 57 } 58 return t; 59 } 60 void solve(int rt) 61 { 62 vis[rt]=1; 63 int d=g[rt].size(); 64 if (d==0) 65 { 66 c[rt]=dp[rt]; 67 return; 68 } 69 for (int i=0;i<d;i++) 70 { 71 int v=g[rt][i].v; 72 if (vis[v]) continue; 73 ll w=g[rt][i].w; 74 ll t=dp[v],t3=dp[rt]; 75 ll t2=find(rt,v)+w; 76 77 78 dp[v]=max(dp[v],t2); 79 dp[rt]=t2-w; 80 c[v]=dp[v]; 81 solve(v); 82 dp[rt]=t3;dp[v]=t; 83 84 } 85 86 } 87 int main() 88 { 89 //freopen("D:\in.txt","r",stdin); 90 while (~scanf("%d",&n)) 91 { 92 init(); 93 for (int i=2;i<=n;i++) 94 { 95 int v,w; 96 scanf("%d%d",&v,&w); 97 node t1={v,w}; 98 g[i].push_back(t1); 99 node t2={i,w}; 100 g[v].push_back(t2); 101 } 102 103 TREEDP(1); 104 c[1]=dp[1]; 105 memset(vis,0,sizeof(vis)); 106 solve(1); 107 for (int i=1;i<=n;i++) 108 printf("%d\n",c[i]); 109 110 } 111 return 0; 112 }
http://acm.hdu.edu.cn/showproblem.php?pid=3586
二分+树形DP;
据说凡是求最大最小值或最小最大值都可以二分确定一个因素,然后验证;
二分上限,树形DP求不超上界切断联络的最小代价;
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<iostream> 5 #include<algorithm> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 const int N=1010; 10 int dp[N]; 11 int n,all; 12 int vis[N]; 13 bool bo[N]; 14 struct node 15 { 16 int v,w; 17 }; 18 vector<node> g[N]; 19 20 const int INF=1000000000; 21 void TREEDP(int rt,int c,int m) 22 { 23 vis[rt]=1; 24 int d=g[rt].size(); 25 26 int t=0; 27 int flag=0; 28 for (int i=0;i<d;i++) 29 { 30 int v=g[rt][i].v; 31 int w=g[rt][i].w; 32 if (vis[v]) continue; 33 TREEDP(v,w,m); 34 if (bo[v]) 35 { 36 bo[rt]=1; 37 break; 38 } 39 t+=dp[v]; 40 flag=1; 41 } 42 if (bo[rt]==1) 43 { 44 if (c<=m) 45 { 46 bo[rt]=0; 47 dp[rt]=c; 48 } 49 } else 50 { 51 if (c<=m) 52 { 53 if (flag) 54 dp[rt]=min(t,c); 55 else dp[rt]=c; 56 }else 57 { 58 if (flag) 59 dp[rt]=t; 60 else bo[rt]=1; 61 62 } 63 } 64 65 } 66 bool solve(int m) 67 { 68 memset(dp,0,sizeof(dp)); 69 memset(vis,0,sizeof(vis)); 70 memset(bo,0,sizeof(bo)); 71 TREEDP(1,INF,m); 72 if (bo[1]==1) return 0; 73 if(dp[1]<=all) return 1; 74 return 0; 75 } 76 void init() 77 { 78 for (int i=1;i<=n;i++) 79 g[i].clear(); 80 } 81 int main() 82 { 83 //freopen("D:\in.txt","r",stdin); 84 while (~scanf("%d%d",&n,&all)) 85 { 86 if (n==0 && all==0) break; 87 init(); 88 int l=0,r=1000; 89 for (int i=2;i<=n;i++) 90 { 91 int u,v,w; 92 scanf("%d%d%d",&u,&v,&w); 93 // r=max(r,w); 94 95 node t1={v,w}; 96 g[u].push_back(t1); 97 node t2={u,w}; 98 g[v].push_back(t2); 99 } 100 int ans=-1; 101 while (r>l) 102 { 103 int m=(l+r)/2; 104 if (solve(m)) 105 { 106 ans=m; 107 r=m; 108 }else l=m+1; 109 } 110 printf("%d\n",ans); 111 112 113 } 114 return 0; 115 }
http://acm.hdu.edu.cn/showproblem.php?pid=1561
dp[i][j]表示以i为根,攻下j个城市的最大获得;
dp[i][j]=max(dp[i][j[,dp[son][k]+dp[i][j-k]);类似于在树上做分组背包;
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<cstdlib> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 const int MAXN=210; 10 int n,m; 11 vector<int > g[MAXN]; 12 int dp[MAXN][MAXN]; 13 //dp[i][j] ,表示以i为根,攻下j个城市的最大获得; 14 int c[MAXN]; 15 void init() 16 { 17 memset(dp,0,sizeof(dp)); 18 for (int i=0;i<=n;i++) 19 { 20 g[i].clear(); 21 } 22 23 } 24 void TREEDP(int rt,int m) 25 { 26 27 int d=g[rt].size(); 28 dp[rt][1]=c[rt]; 29 for (int i=0;i<d;i++) 30 { 31 32 int c=g[rt][i]; 33 if (m>1) 34 TREEDP(c,m-1); 35 for (int j=m;j>0;j--) 36 { 37 int v=j+1; 38 for (int k=1;k<v;k++) 39 if (dp[rt][v]<dp[rt][v-k]+dp[c][k]) 40 { 41 dp[rt][v]=dp[rt][v-k]+dp[c][k]; 42 } 43 44 } 45 } 46 47 } 48 int main() 49 { 50 // freopen("D:\in.txt","r",stdin); 51 while (~scanf("%d%d",&n,&m)) 52 { 53 if (n==0 && m==0) break; 54 c[0]=0; init(); 55 for (int i=1;i<=n;i++) 56 { 57 int v; 58 scanf("%d%d",&v,&c[i]); 59 g[v].push_back(i); 60 } 61 TREEDP(0,m+1); 62 printf("%d\n",dp[0][m+1]); 63 64 } 65 return 0; 66 }
http://acm.hdu.edu.cn/showproblem.php?pid=1011
同上;注意特判;
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<iostream> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 10 const int MAXN=110; 11 int n,m; 12 vector<int > g[MAXN]; 13 int c[MAXN],w[MAXN]; 14 int dp[MAXN][MAXN]; 15 int vis[MAXN]; 16 //dp[i][j] 以i为根花费j能获得的最大利益; 17 18 void TREEDP(int rt) 19 { 20 21 vis[rt]=1; 22 int d=g[rt].size(); 23 for (int i=c[rt];i<=m;i++) dp[rt][i]=w[rt]; 24 for (int i=0;i<d;i++) 25 { 26 int son=g[rt][i]; 27 if (vis[son]==0) 28 { 29 TREEDP(son); 30 31 for (int j=m;j>=c[rt];j--) 32 { 33 34 for (int k=1;j+k<=m;k++) 35 { 36 if (dp[son][k]) 37 dp[rt][j+k]=max(dp[rt][j+k],dp[rt][j]+dp[son][k]); 38 39 } 40 } 41 } 42 43 } 44 } 45 void init() 46 { 47 memset(dp,0,sizeof(dp)); 48 for (int i=0;i<=n;i++) g[i].clear(); 49 memset(vis,0,sizeof(vis)); 50 } 51 int main() 52 { 53 //freopen("D:\in.txt","r",stdin); 54 while (~scanf("%d%d",&n,&m)) 55 { 56 if (n==-1 && m==-1) break; 57 init(); 58 for (int i=1;i<=n;i++) 59 { 60 int a,b; 61 scanf("%d%d",&a,&b); 62 c[i]=(a+19)/20; 63 // if (a%20) c[i]+=1; 64 w[i]=b; 65 } 66 for (int i=0;i<n-1;i++) 67 { 68 int u,v; 69 scanf("%d%d",&u,&v); 70 g[u].push_back(v); 71 g[v].push_back(u); 72 } 73 if (m==0) 74 { 75 printf("0\n"); 76 continue; 77 } 78 TREEDP(1); 79 printf("%d\n",dp[1][m]); 80 81 } 82 return 0; 83 }
http://acm.hdu.edu.cn/showproblem.php?pid=4003
题意差不多,但要特别处理0的情况;
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<iostream> 6 #include<vector> 7 #include<cmath> 8 using namespace std; 9 const int N=10010; 10 int dp[N][11]; 11 int n,s,num; 12 int vis[N]; 13 struct node 14 { 15 int v,w; 16 }; 17 vector<node > g[N]; 18 const int INF=1000000000; 19 20 21 void TREEDP(int rt) 22 { 23 vis[rt]=1; 24 int d=g[rt].size(); 25 for (int i=0;i<d;i++) 26 { 27 int v=g[rt][i].v; 28 int w=g[rt][i].w; 29 if (vis[v]) continue; 30 TREEDP(v); 31 for (int j=num;j>=0;j--) 32 { 33 int t=INF; 34 for (int k=0;k<=j;k++) 35 { 36 37 if (j-k==0) 38 t=min(t,dp[rt][k]+dp[v][j-k]+w*2); 39 else t=min(t,dp[rt][k]+dp[v][j-k]+w*(j-k)); 40 41 } 42 dp[rt][j]=t; 43 } 44 } 45 46 } 47 void init() 48 { 49 memset(dp,0,sizeof(dp)); 50 memset(vis,0,sizeof(vis)); 51 for (int i=0;i<=n;i++) g[i].clear(); 52 53 } 54 int main() 55 { 56 //freopen("D:\in.txt","r",stdin); 57 while (~scanf("%d%d%d",&n,&s,&num)) 58 { 59 init(); 60 for (int i=0;i<n-1;i++) 61 { 62 int u,v,w; 63 scanf("%d%d%d",&u,&v,&w); 64 node t1={v,w}; 65 g[u].push_back(t1); 66 node t2={u,w}; 67 g[v].push_back(t2); 68 69 } 70 // init_dp(s); 71 memset(vis,0,sizeof(vis)); 72 TREEDP(s); 73 printf("%d\n",dp[s][num]); 74 } 75 return 0; 76 }
http://acm.hdu.edu.cn/showproblem.php?pid=2242
这题主要还是缩点;树形DP,就随便搞一下;
#include<cstdio> #include<iostream> #include<cstdlib> #include<cstdlib> #include<algorithm> #include<stack> using namespace std; const int M=20005; const int N=10005; const int INF=1000000000; struct node { int u,v; int next; }edge[M*2],edge1[M*2]; int head[N],tol,cnt,dfn[N],low[N],vis[N],belong[N]; int toll,head1[N],val[N],val1[N]; int n,m,SUM,Min,scc; stack<int > S; void insert(int a,int b) { node v={a,b,head[a]}; edge[tol]=v; head[a]=tol++; } void insert1(int a,int b) { node v={a,b,head1[a]}; edge1[toll]=v; head1[a]=toll++; } void tarjan(int u,int father) { int j,v,flag; dfn[u]=low[u]=cnt++; vis[u]=1; S.push(u); flag=0; for (j=head[u];j!=-1;j=edge[j].next) { v=edge[j].v; if (v==father && !flag) { flag=1;continue; } if (!vis[v]) tarjan(v,u); low[u]=min(low[u],low[v]); } if (dfn[u]==low[u]) { scc++; do { v=S.top();S.pop(); belong[v]=scc; val[scc]+=val1[v]; } while (v!=u) ; } } int dfs(int u,int father) { int j,v,sum; sum=val[u]; for (j=head1[u];j!=-1;j=edge1[j].next) { v=edge1[j].v; if (v==father) continue; sum+=dfs(v,u); } Min=min(Min,abs(SUM-2*sum)) ; return sum; } int main() { while (~scanf("%d%d",&n,&m)) { memset(head,-1,sizeof(head)); tol=cnt=0; SUM=0; for (int i=0;i<n;i++) { scanf("%d",&val1[i]); SUM+=val1[i]; } for (int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); insert(u,v); insert(v,u); } memset(vis,0,sizeof(vis)); memset(val,0,sizeof(val)); scc=0; while (!S.empty())S.pop(); tarjan(0,0); if (scc==1) { printf("impossible\n"); continue; } toll=0; memset(head1,-1,sizeof(head1)); for (int i=0;i<tol;i++) { int a=edge[i].u; int b=edge[i].v; if (belong[a]!=belong[b]) insert1(belong[a],belong [b]); } Min=INF; dfs(1,0); printf("%d\n",Min); } return 0; }