プログラミングコンテストチャレンジブック 题解

题目大意:从 \(n\) 根木棒里选出六根拼成两个合法的三角形,使这两个三角形的周长和最大。

考虑贪心,证明在后面。

首先我们要知道一个三角形基本定理:较短两边长度之和大于最长边
那我们就根据这个定理先去寻找最大三角形的最长边。
先排序,然后循环枚举,对于每个 \(a_i\),可以寻找到的最大的其余两边为 \(a_{i-1}\)\(a_{i-2}\),如果该组不合法,那么其余组也不合法,否则我们就保存当前的 \(i\),把最大的两组加起来输出即可。

但是这题还有个比较坑的地方,两组合法三角形的边可能产生冲突,解决方法也很简单:从最大三角形的最长边往下找六条边,只要里面还有一种组合合法那就是最优解,否则无解。

证明
设可以选的最大边为为 \(s_m\),那么对于一组可选边 \(s_i\)\(s_j\),会有以下几种情况:

  • \(s_i\)\(s_j\) 不冲突,那么 \(s_i\)\(s_m\) 肯定也不冲突,所以选 \(s_i\)\(s_m\)
  • \(s_i\)\(s_j\) 冲突,但 \(s_j\)\(s_m\) 不冲突,那么选 \(s_j\)\(s_m\) 最优。
  • \(s_i\)\(s_j\) 冲突,但 \(s_i\)\(s_m\) 不冲突,那么选 \(s_i\)\(s_m\) 最优。
  • \(s_i\)\(s_j\) 冲突,并且它们与 \(s_m\) 都有冲突,那么选哪组都对答案无影响。

证毕。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a,s,d[100005],f[100005];
ll ans,sum,cnt,maxn;
int main() {
	scanf("%lld",&a);
	for(int i=1;i<=a;i++){
		scanf("%lld",&d[i]);
	} 
	sort(d+1,d+a+1);
	for(int i=3;i<=a;i++){
		if(d[i]<d[i-1]+d[i-2]){
			f[++cnt]=i;
		}
	}
	for(int i=1;i<=cnt;i++){
		if(f[cnt]-f[i]>=3){
			maxn=i;
		}
	}
	if(maxn!=0){
		ans=d[f[cnt]]+d[f[cnt]-1]+d[f[cnt]-2]+d[f[maxn]]+d[f[maxn]-1]+d[f[maxn]-2];
	}
	if(f[cnt]>=6){
		ll num1=d[f[cnt]-5],num2=d[f[cnt]-4],num3=d[f[cnt]-3],num4=d[f[cnt]-2],num5=d[f[cnt]-1],num6=d[f[cnt]];
		sum=num1+num2+num3+num4+num5+num6;
		if(num1+num2>num3&&num4+num5>num6){
			ans=sum;
		}
		if(num1+num2>num4&&num3+num5>num6){
			ans=sum;
		}
		if(num1+num2>num5&&num3+num4>num6){
			ans=sum;
		}
		if(num1+num2>num6&&num3+num4>num5){
			ans=sum;
		}
		if(num1+num3>num4&&num2+num5>num6){
			ans=sum;
		}
		if(num1+num3>num5&&num2+num4>num6){
			ans=sum;
		}
		if(num1+num3>num6&&num2+num4>num5){
			ans=sum;
		}
		if(num1+num4>num5&&num2+num3>num6){
			ans=sum;
		}
		if(num1+num4>num6&&num2+num3>num5){
			ans=sum;
		}
		if(num1+num5>num6&&num2+num3>num4){
			ans=sum;
		}
	} 
	printf("%lld\n",ans);
    return 0;
}
posted @ 2024-06-07 19:51  Linurve10  阅读(23)  评论(0)    收藏  举报