题目是leetcode第76场双周赛T4结点序列的最大得分
数据范围较大,暴力枚举dfs的话会超时,题目需要我们构造一个序列,由四个结点三条边组成,对于这种“三元组类”的问题,我们一般是选择枚举中间元素,在这个题中我们枚举三条边的中间那条边。
假设序列为a-x-y-b(-表示为一条边),我们枚举edges中的每条边作为序列的中间那条边,即x-y,需要注意的是
- 由于不能出现重复的元素,因此与x相邻的点中,不能选择与y和b相同的点,因此我们保留分数最大的三个点,a必定在这三个点中,同理,保留y相邻的最大的三个点,b一定在这三个点中。
- 图用邻接表存储,因此遍历到g[i]点时,我们选取与点i相邻的,得分最大的三个点,并对每个点进行相同的操作,如果与该点相邻的点不足三个,则不做处理
- 预处理完后,枚举所有的边,并在此条边的两个结点处分别枚举a和b的值,更新最大的得分,直到枚举完所有的边
int maximumScore(vector<int>& scores, vector<vector<int>>& edges) {
int n=scores.size();
vector<vector<pair<int,int>>>g(n); //邻接表,存储相邻的结点和得分
for(auto& e:edges){
int x=e[0],y=e[1];
g[x].push_back(make_pair(-scores[y],y)); //与点x相邻的y结点和其得分
g[y].push_back(make_pair(-scores[x],x));
}
for(auto& x:g){ //遍历每个结点
if(x.size()>3){ //与结点x相邻的结点的个数大于3
nth_element(x.begin(),x.begin()+3,x.end()); //排序,找到第3小的元素,且前面的元素都比他小
x.resize(3); //删去多余三个的元素
}
}
int ans=-1;
for(auto& e:edges){ //遍历每条边
int x=e[0],y=e[1]; //确定x结点和y结点
for(auto& [score_a,a]:g[x]){ //从x结点相邻的结点选取分数最大的结点a
for(auto& [score_b,b]:g[y]){ //从y结点相邻的结点中选取分数最大的结点b
if(a!=y&&b!=x&&a!=b){ // a不能等于y,b,b不能等于x,a
ans=max(ans,-score_a + scores[x] + scores[y] - score_b); //更新最大的值,注意存储的是得分的负值
}
}
}
}
return ans;
}