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

PerchLootie發表於2024-06-07

題目大意:從 $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;
}

相關文章