两家银行称为间接邻居 他们的距离是2且中点银行没有被hack
每次hack完一家银行后 他的邻居和间接邻居的防御值都+1
开始你可以任意选一家银行hack 接下来你只能hack已经hack过的银行的邻居
求最小攻击值能hack掉所有银行
题解:
这道题是细节题
令mix1为最大的防御值 mix2为次大的防御值
答案很明显 只有三种可能 mix1 mix1+1 mix1+2
当只有一家银行时 答案就是mix1 return 0
当只有两家银行时 答案就是max( mix1 ,mix2+1 ) return 0
当所有的点防御值都一样时 当银行呈烟花状时(一个银行是其他所有银行的邻居) 那么我们先hack这家银行 答案就是 mix1+1 return 0
否则 答案就是mix1+2 return 0
当最大的防御值的数大于等于3个时 如果呈烟花状(一个烟花包含所有最大的防御值的银行) 答案就是mix1+1
否则 答案就是mix1+2
当最大的防御值的数等于2个时 如果这两个点距离小于等于2 那么答案就是mix1+1
否则 答案就是mix1+2
当最大的防御值的数等于1时 如果以这个点为中心和所有次大的防御值的银行呈烟花状 答案就是 mix1
否则 答案就是 max( mix1 , mix2+2 )
还有一种暴力做法(我听了想打人)
把这些点都放进multiset里面 然后for每个点 对于每个点 他相邻的点都+1 然后把这个点和相邻的都删掉 再从multiset中找出最大的+2 再把删去的点放回去
这样的做法复杂度是nlongn 因为每个点被放进去的次数是这个点的du+1
这里放分类讨论的代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<deque>
using namespace std;
struct node{
int to,nex;
}edge[600005];
int head[300005],cnt,num[300005],du[300005];
void add(int u,int v){
edge[cnt].to=v;
edge[cnt].nex=head[u];
head[u]=cnt++;
}
deque<int>sp;
int vis[300005];
int main(){
int n,i,j,x,y,mix1=-1000000001,mix2=-1000000001;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&num[i]);
if(num[i]>=mix1){
mix2=mix1;
mix1=num[i];
}
else if(num[i]>=mix2)mix2=num[i];
}
int num1=0,num2=0;
for(i=1;i<=n;i++){
if(mix1==num[i])num1++;
else if(mix2==num[i])num2++;
}
int td=0,lab=0,mis=0;;
memset(head,-1,sizeof(head));
for(i=1;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
if(num[x]==mix1){
du[y]++;
if(du[y]>mis){
mis=du[y];
lab=y;
}
}
if(num[y]==mix1){
du[x]++;
if(du[x]>mis){
mis=du[x];
lab=x;
}
}
td=max(td,du[x]);
td=max(td,du[y]);
}
if(num1==n){
if(n==1)printf("%d\n",mix1);
else if(td==n-1)printf("%d\n",mix1+1);
else printf("%d\n",mix1+2);
return 0;
}
if(n==1){
printf("%d\n",mix1);
return 0;
}
else if(n==2){
if(num[1]==num[2])printf("%d\n",num[1]+1);
else printf("%d\n",mix1);
return 0;
}
if(num1>=3){
if(mis==num1||(mis==num1-1&&num[lab]==mix1))printf("%d\n",mix1+1);
else printf("%d\n",mix1+2);
}
else if(num1==2){
for(i=1;i<=n;i++){
if(num[i]==mix1)break;
}
int flag=1;
vis[i]=1;
sp.push_back(i);
while(!sp.empty()){
int f=sp.front();
sp.pop_front();
if(vis[f]>=4)continue;
if(num[f]==mix1&&f!=i){
flag=0;
break;
}
for(j=head[f];~j;j=edge[j].nex){
int v=edge[j].to;
if(vis[v])continue;
vis[v]=vis[f]+1;
sp.push_back(v);
}
}
if(flag){
printf("%d\n",mix1+2);
}
else printf("%d\n",mix1+1);
}
else{
int nums=0;
for(i=1;i<=n;i++){
if(num[i]==mix1)break;
}
for(j=head[i];~j;j=edge[j].nex){
if(num[edge[j].to]==mix2)nums++;
}
if(nums==num2)printf("%d\n",mix1);
else printf("%d\n",max(mix1,mix2+2));
}
return 0;
}