题意:给定一棵含有n片叶子的树,告诉你每片叶子到其它叶子的距离,求整棵树的权值。
题解:1、假设最后已经生成一棵完整的树,其中某个结点上必定会有至少两片叶子,否则该结点可以直接去掉而不影响最后的结果。
2、对于这种有两片叶子以上上作为孩子的结点,除该子树的所有的结点到它的叶子都会经过该节点,所以可以直接将该子树缩点变成一个大点,记录这个结点到其他所有点的距离。
3、反复进行2这种操作,直至最后只剩一个结点。
View Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int n,go[200][200]; 6 bool vis[200]; 7 bool check(int a,int b,int &sa) 8 { 9 bool flag=true; 10 for(int i=0;i<n;i++) 11 { 12 if(!vis[i]&&i!=a&&i!=b) 13 { 14 if(flag) 15 { 16 sa=go[a][i]-(go[a][i]+go[b][i]-go[a][b])/2; 17 flag=false; 18 } 19 else if(sa!=go[a][i]-(go[a][i]+go[b][i]-go[a][b])/2) 20 return false; 21 } 22 } 23 return true; 24 } 25 int main() 26 { 27 //freopen("data.txt","r",stdin); 28 while(scanf("%d",&n),n) 29 { 30 memset(vis,false,sizeof(vis)); 31 for(int i=0;i<n;i++) 32 { 33 go[i][i]=0; 34 for(int j=i+1;j<n;j++) 35 scanf("%d",&go[i][j]),go[j][i]=go[i][j]; 36 } 37 int ans=0,sa,a,b; 38 while(1) 39 { 40 bool flag=false; 41 for(a=0;a<n;a++) 42 { 43 if(vis[a]) 44 continue; 45 for(b=a+1;b<n;b++) 46 { 47 if(vis[b]) 48 continue; 49 if(check(a,b,sa)) 50 { 51 flag=true; 52 break; 53 } 54 } 55 if(flag) 56 break; 57 } 58 if(!flag) 59 break; 60 ans+=go[a][b]; 61 vis[a]=vis[b]=true; 62 for(int j=0;j<n;j++) 63 { 64 if(!vis[j]) 65 go[j][n]=go[n][j]=go[j][a]-sa; 66 } 67 n++; 68 } 69 printf("%d\n",ans); 70 } 71 return 0; 72 }