标签:合成 return 最大 ret 最大的 黑点 abi 证明 names
题目大意:
输入一棵n个点的树,每个节点是黑色或白色,现在希望选出m个黑点,使得这m个黑点之间的距离的最大值最小,输出最小距离。
思路:
我先想到了二分距离,要从[0,n-1]开始(左端点不能从1开始,更不能从m-1开始,这里我wa了9次)。假设二分出的距离是mid,需要分两种情况:
正确性证明:
a.每一个直径为偶数的树都以一个点为中心。
假设设一棵树T有n个点,直径为2*m,且任意的点i都存在一个j使得i,j的距离大于m。若有一个点k使得两个点j1,j2到k的距离都大于m,则j1,j2的距离就大于2*m,矛盾。若每一个点都使得仅有一个点到其距离大于m,则取这 样的两对点i,j和k,l,显然树上还有联通这对点的一条路径,则四条路径(i,l),(i,k),(j,k),(j,l)中一定有一条要经过边(i,j)和(k,l),这样它们的距离就大于2*m了,矛盾。
所以存在一个中心点。
b.每一个直径为奇数的树都以一条边的两个点为中心。
设一棵树T有n个点,直径为2*m+1,找到一条直径(x1,x2,...,xm+1,xm+2,...x2*m+2),将最中间的xm+1,xm+2合成一个点y,删去边(xm+1,xm+2),将与xm+1,xm+2连的边连向y,即证明所有点到y的距离都不大于m。假设存在点k使dis(k,y)大于m,不妨设k原来与xm+2连,则k到x1的距离为dis(x1,xm+2)+dis(k,y),大于2*m+1,矛盾。
所以树T以xm+1,xm+2为中心。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 6 using namespace std; 7 8 int n,m,bianshu=0,cor[200],head[200]; 9 int que[2000],st,ed,cnt,used[200],dis[200],yy[200][3]; 10 struct node 11 { 12 int zhong,next; 13 node() 14 { 15 zhong=0; 16 next=0; 17 } 18 }bian[200*5]; 19 20 void comq(int x) 21 { 22 st++; 23 used[x]=1; 24 que[st]=x; 25 return ; 26 } 27 28 void jiabian(int qi,int zh) 29 { 30 bianshu++; 31 bian[bianshu].next=head[qi]; 32 bian[bianshu].zhong=zh; 33 head[qi]=bianshu; 34 return ; 35 } 36 37 bool check1(int x) 38 { 39 //printf("X=%d\n",x); 40 int maxx=0; 41 for(int i=1;i<=n;i++) 42 { 43 memset(used,0,sizeof(used)); 44 memset(que,0,sizeof(que)); 45 memset(dis,0,sizeof(dis)); 46 st=0; 47 ed=0; 48 cnt=0; 49 comq(i); 50 if(cor[i]==1)cnt++; 51 dis[i]=0; 52 while(st!=ed) 53 { 54 ed++; 55 int dang=que[ed]; 56 if(dis[dang]>=(x/2))break; 57 int k=head[dang]; 58 while(k) 59 { 60 if(!used[bian[k].zhong]) 61 { 62 if(cor[bian[k].zhong]==1)cnt++; 63 comq(bian[k].zhong); 64 dis[bian[k].zhong]=dis[dang]+1; 65 } 66 k=bian[k].next; 67 } 68 } 69 maxx=max(cnt,maxx); 70 } 71 if(maxx>=m)return true; 72 else return false; 73 } 74 75 bool check2(int x) 76 { 77 x--; 78 int maxx=0; 79 for(int i=1;i<n;i++) 80 { 81 memset(used,0,sizeof(used)); 82 memset(que,0,sizeof(que)); 83 memset(dis,0,sizeof(dis)); 84 st=0; 85 ed=0; 86 cnt=0; 87 comq(yy[i][1]); 88 if(cor[yy[i][1]]==1)cnt++; 89 dis[yy[i][1]]=0; 90 comq(yy[i][2]); 91 if(cor[yy[i][2]]==1)cnt++; 92 dis[yy[i][2]]=0; 93 while(st!=ed) 94 { 95 ed++; 96 int dang=que[ed]; 97 if(dis[dang]>=(x/2))break; 98 int k=head[dang]; 99 while(k) 100 { 101 if(!used[bian[k].zhong]) 102 { 103 if(cor[bian[k].zhong]==1)cnt++; 104 used[bian[k].zhong]=1; 105 st++; 106 que[st]=bian[k].zhong; 107 dis[bian[k].zhong]=dis[dang]+1; 108 } 109 k=bian[k].next; 110 } 111 } 112 maxx=max(cnt,maxx); 113 } 114 if(maxx>=m)return true; 115 else return false; 116 } 117 118 bool ok(int x) 119 { 120 if(x&1)return check2(x); 121 else return check1(x); 122 } 123 124 int main() 125 { 126 scanf("%d%d",&n,&m); 127 for(int i=1;i<=n;i++)scanf("%d",&cor[i]); 128 for(int i=1;i<n;i++) 129 { 130 int a,b; 131 scanf("%d%d",&a,&b); 132 yy[i][1]=a; 133 yy[i][2]=b; 134 jiabian(a,b); 135 jiabian(b,a); 136 } 137 if((m==1)||(n==1)) 138 { 139 printf("0\n"); 140 return 0; 141 } 142 int l=0; 143 int r=n; 144 while(l<r) 145 { 146 int mid=(l+r)>>1; 147 if(ok(mid))r=mid; 148 else l=mid+1; 149 } 150 printf("%d\n",r); 151 return 0; 152 }
标签:合成 return 最大 ret 最大的 黑点 abi 证明 names
原文地址:https://www.cnblogs.com/LiqgNonqfu/p/9978471.html