题目大意:
现有N根长度各异的木棍(3 ≤ N ≤ 2000),问共可以组成多少个不同的三角形。
现有多个测例(测例数会告诉你),每个测例中给定N以及N根木棍的长度(每根木棍长度范围为[1, 10^9]),对于每个测例都打印出可以组成的三角形的总数量。
注释代码:
/*
* Problem ID : LOJ 1307 Counting Triangles
* Author : Lirx.t.Una
* Language : C++
* CPU : 1.384
* Memory : 1696
*/
#include <algorithm>
#include <iostream>
#include <cstdio>
//maximum number of sticks
//木棍的最大数量
#define MAXSTICKN 2001
using namespace std;
int a[MAXSTICKN];//存储每根木棍的数量
int
main() {
int nscn, iscn;
int n;//木棍数量
int i, j;//计数变量
int lft, rht;//临时区间界限
int ans;
scanf("%d", &nscn);
iscn = 0;
while ( nscn-- ) {
scanf("%d", &n);
for ( i = 0; i < n; i++ )
scanf("%d", a + i);
sort(a, a + n);//排序后以便二分查找
//从左往右扫描,先确定两根木棍i、j
//再根据三角形规则确定后面的第三根
for ( ans = 0, i = 0; i < n - 2; i++ )
for ( j = i + 1; j < n - 1; j++ ) {
lft = a[j] - a[i] + 1;//第三边一定大于前两遍之差(+1表示大于)
rht = a[i] + a[j] - 1;//第三遍一定小于前两遍之和(-1表示小于)
lft = lower_bound(a, a + n, lft) - a;//二分找出大于等于lft的第一个元素在数组中的位置
rht = upper_bound(a + lft, a + n, rht) - a - 1;//二分找出大于rht的第一个元素在数组中的位置
//两个重要的剪枝,如果lft和rht都在j前面表示之前已经计算过了,可不用重复计算
if ( lft <= j )
lft = j + 1;
if ( rht <= j )//rht小于等于j就表示无第三根可以组成三角形的木棍了,因为可行区间在[lft, rht]上
continue;
if ( lft <= rht )//如果lft大于rht也表示这样的三角形不存在了
ans += rht - lft + 1;
}
printf("Case %d: %d\n", ++iscn, ans);
}
return 0;
}
无注释代码:
#include <algorithm>
#include <iostream>
#include <cstdio>
#define MAXSTICKN 2001
using namespace std;
int a[MAXSTICKN];
int
main() {
int nscn, iscn;
int n;
int i, j;
int lft, rht;
int ans;
scanf("%d", &nscn);
iscn = 0;
while ( nscn-- ) {
scanf("%d", &n);
for ( i = 0; i < n; i++ )
scanf("%d", a + i);
sort(a, a + n);
for ( ans = 0, i = 0; i < n - 2; i++ )
for ( j = i + 1; j < n - 1; j++ ) {
lft = a[j] - a[i] + 1;
rht = a[i] + a[j] - 1;
lft = lower_bound(a, a + n, lft) - a;
rht = upper_bound(a + lft, a + n, rht) - a - 1;
if ( lft <= j )
lft = j + 1;
if ( rht <= j )
continue;
if ( lft <= rht )
ans += rht - lft + 1;
}
printf("Case %d: %d\n", ++iscn, ans);
}
return 0;
}
单词解释:
triangle:n, 三角,三角形
stick:n, 木棍
valid:adj, 有效的,合法的,正当的