This commit is contained in:
Zengtudor 2025-07-16 08:56:08 +08:00
parent 6573de0ce0
commit 714f9830be
8 changed files with 164 additions and 0 deletions

2
src/7/16/Area0.in Normal file
View File

@ -0,0 +1,2 @@
4
5 6 7 10

1
src/7/16/Area0.out Normal file
View File

@ -0,0 +1 @@
3394819

2
src/7/16/Area1.in Normal file
View File

@ -0,0 +1,2 @@
5
18 4 17 5 1

1
src/7/16/Area1.out Normal file
View File

@ -0,0 +1 @@
15579794

2
src/7/16/Area2.in Normal file
View File

@ -0,0 +1,2 @@
10
10 18 12 2 14 17 6 12 7 10

1
src/7/16/Area2.out Normal file
View File

@ -0,0 +1 @@
454559413

106
src/7/16/T633664.md Normal file
View File

@ -0,0 +1,106 @@
### 解题思路
这道题要求使用所有围栏(由不同板材拼接而成)构建一个三角形广场,并最大化三角形面积。围栏的总长度是固定的,为 \( T \)。三角形的三条边由围栏分组拼接而成,每条边的长度必须严格小于 \( T/2 \) 才能满足三角形条件(任意两边之和大于第三边)。问题转化为将围栏分成三组,使得每组和都小于 \( T/2 \),并计算最大可能的三角形面积。
### 算法步骤
1. **计算围栏长度**:遍历所有不同板材对,计算围栏长度 \( S_i + S_j \)\( i \neq j \)),存储到数组 `lengths` 中。
2. **计算总长度 \( T \)**:对所有围栏长度求和,或通过公式 \( T = (n-1) \times \sum S_i \) 计算。
3. **动态规划分组**
- 初始化二维数组 `dp_old``dp_old[i][j] = true` 表示第一组和为 \( i \)、第二组和为 \( j \) 是可行的。
- 对于每个围栏长度,更新状态:将当前围栏放入第一组、第二组或第三组,并确保新的组和不超过 \( (T-1)/2 \)(即严格小于 \( T/2 \))。
- 使用滚动数组优化空间,每次更新 `dp_new` 并赋值给 `dp_old`
4. **检查可行解并计算最大面积**
- 遍历所有状态 `(i, j)`,如果 `dp_old[i][j] = true` 且第三组和 \( c = T - i - j < T/2 \)则三条边 \( (i, j, c) \) 可构成三角形
- 使用海伦公式计算面积:半周长 \( s = T/2 \),面积 \( A = \sqrt{s(s-i)(s-j)(s-c)} \)。
- 记录最大面积,乘以 10000 后向下取整输出;若无解,输出 -1。
### 复杂度分析
- **时间**:围栏总数 \( m = n(n-1)/2 \leq 45 \),动态规划状态数 \( O(m \times (T/2)^2) \),最坏情况 \( T \leq 1800 \),状态数约 3645 万,可接受。
- **空间**:使用两个二维数组,大小 \( O((T/2)^2) \),约 810000 个布尔值。
### 代码实现
```cpp
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> S(n);
for (int i = 0; i < n; i++) {
cin >> S[i];
}
vector<int> lengths;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
lengths.push_back(S[i] + S[j]);
}
}
int m = lengths.size();
int T_total = 0;
for (int L : lengths) {
T_total += L;
}
int a_max = (T_total - 1) / 2;
int b_max = a_max;
vector<vector<bool>> dp_old(a_max + 1, vector<bool>(b_max + 1, false));
dp_old[0][0] = true;
for (int k = 0; k < m; k++) {
int L = lengths[k];
vector<vector<bool>> dp_new(a_max + 1, vector<bool>(b_max + 1, false));
for (int i = 0; i <= a_max; i++) {
for (int j = 0; j <= b_max; j++) {
if (dp_old[i][j]) {
if (i + L <= a_max) {
dp_new[i + L][j] = true;
}
if (j + L <= b_max) {
dp_new[i][j + L] = true;
}
dp_new[i][j] = true;
}
}
}
dp_old = dp_new;
}
double max_area = -1.0;
for (int i = 0; i <= a_max; i++) {
for (int j = 0; j <= b_max; j++) {
if (dp_old[i][j]) {
int c = T_total - i - j;
if (c < T_total / 2.0) {
double s = T_total / 2.0;
double area = sqrt(s * (s - i) * (s - j) * (s - c));
if (area > max_area) {
max_area = area;
}
}
}
}
}
if (max_area < 0) {
cout << -1 << endl;
} else {
long long result = static_cast<long long>(max_area * 10000);
cout << result << endl;
}
return 0;
}
```
### 代码说明
1. **输入处理**:读取板材数量 \( n \) 和长度数组 \( S \)。
2. **围栏生成**:计算所有不同板材对的围栏长度并存储。
3. **动态规划初始化**`dp_old[0][0] = true` 表示初始状态无围栏时两组和均为0
4. **状态转移**:对每个围栏,尝试放入三组之一,更新状态数组。
5. **面积计算**:遍历所有可行状态,检查三角形条件,用海伦公式计算面积并记录最大值。
6. **输出**:最大面积乘以 10000 后向下取整输出,若无解输出 -1。

49
src/7/16/T633664f.cpp Normal file
View File

@ -0,0 +1,49 @@
#include <cmath>
#include <cstdint>
#include <iostream>
#include <istream>
#include <unordered_set>
#include <vector>
using ll = int64_t;
ll n;
std::vector<ll> s;
std::vector<ll> edg;
double getArea(double a,double b,double c){
double s = a+b+c;
return std::sqrt(s*(s-a)*(s-b)*(s-c));
}
void dfs(ll depth){
for(ll i=0;i<edg.size()-2+depth;i++){
ll sum{};
}
}
int main(){
std::iostream::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
std::cin>>n;
s.reserve(n+1);
edg.reserve(n*(n-1)/2+1);
for(ll i=0;i<n;i++){
ll tmp;
std::cin>>tmp;
s.emplace_back(tmp);
}
for(ll i=0;i<s.size();i++){
for(ll j=0;j<s.size();j++){
if(i==j)continue;
edg.emplace_back(i+j);
}
}
}