题意:
给一个n个点,n-1条边的连通图,每个点一个值,一开始选任意一点开始访问,访问一点后,这个点从图中消失,和它相邻和相距一个点的点+1,接下来能访问和它相邻的点,求访问的点的最大值。
思路:
选定一个点开始访问,ans={,它,周围一圈+1,其余+2}
当max存在1个以上,ans=max+1或max+2.
如果存在一个点,所有max都在其1格内 ans=max+1,or ans=max+2
max只有一个时,如果所有max-1都在其1格范围内,ans=max or ans=max+1;
其他情况都是ans=max
检查了四个小时的原因(!!):
1.最小值为-1e9,max的一开始初始值设了0(数据范围)
2.一开始的思路没有化到最简,还dfs了点的第2层,十分烦(当感觉自己的思路有点烦时,要再多想想)
3.(最最浪费时间的一点)最最开始的思路错了,认为要第一个访问的点一定要是最大值的点。(要保证每一步的准确性)
代码:
#include<iostream> #include<vector> #include<queue> #include<cstring> #include<algorithm> #include<cmath> #include<cstdio> #include<map> #define INF 0x7f7f7f7f #define MAX_INT 0x7fffffff #define pi 3.1415926 typedef long long LL; typedef unsigned int uint; using namespace std; vector<int>t[300005]; int num[300005]; int ns,ni; int maxx=-MAX_INT,nma; /* 当max存在1个以上,ans=max+1或max+2. 如果存在一个max,所有max都在其1格内 ans=max+1,or ans=max+2 max只有一个时,如果所有max-1都在其1格范围内,ans=max or ans=max+1; 其他情况都是ans=max */ int cnt; int search(int pos,int c){ int si=t[pos].size(); if(!c){ for(int i=0;i<si;i++){ if(num[t[pos][i]]==maxx-1)cnt++; } if(cnt==nma)return 0; else return 1; } else{ for(int i=0;i<si;i++){ if(num[t[pos][i]]==maxx){ cnt++; } } if(cnt<ns)return 2; else return 1; } } int main(){ int n;register int i,a,b; scanf("%d",&n); for(i=1;i<=n;i++){ scanf("%d",&num[i]); if(maxx<num[i]){ maxx=num[i]; } } for(i=1;i<=n;i++) if(num[i]==maxx){ns++;ni=i;} else if(num[i]==maxx-1)nma++; for(i=1;i<n;i++){ scanf("%d%d",&a,&b); t[a].push_back(b); t[b].push_back(a); } int ans=5; if(ns>1){ for(i=1;i<=n;i++){ cnt=0; if(num[i]==maxx)cnt++; ans=min(ans,search(i,1)); } } else{ ans=search(ni,0); } printf("%d\n",ans+maxx); return 0; }