1.6.1 三角形
n根棍子,i号棍子的长度为ai。从中选出3根棍子组成周长尽可能长的三角形。输出最大的周长,如果不能组成三角形,输出0。
限制条件:3 <= n <= 100;1 <= ai <= 10^6
O(n^3)
#include <iostream>
using namespace std;
int numberset[100];
int main()
{
int num, ans = 0;
cin >> num;
for(int i = 0; i < num;i++)
{
cin >> numberset[i];
}
for(int i = 0;i < num;i++)
{
//使得i < j < k 避免重复
for(int j = i + 1;j < num;j++)
{
for(int k = j + 1;k < num;k++)
{
int len = numberset[i] + numberset[j] + numberset[k];
int maxsidelength = max(numberset[i], max(numberset[j], numberset[k]));
int rest = len - maxsidelength;
/**只要两边之和大于第三边就可以构成三角形
***为什么不用考虑差的情况**/
if(maxsidelength < rest)//两边之和大于第三边
{
ans = max(len, ans);
}
}
}
}
cout << ans << endl;
return 0;
}
白书上说还有一种O(nlogn)的做法,查了一下
与上面的重要区别就是读入边长后先进行排序,因为我们要做的判断是两边之和>第三边(max),那么排序后如果总的Max值比其后两边长的和还要大,就不必再依次判断,含有这个总max的组合一定是无法组成三角形的。这是就再重复上面的过程,对次大,次次大……进行判断。同样的,如果max比其后两边的和要小,一次判断说明可以组成三角形。
(因为我们的题目求的是周长尽可能大,也就是边长的选用要尽可能大)
#include <iostream>
#include <algorithm>
using namespace std;
int numberset[100];
int main()
{
int num, ans = 0;
cin >> num;
for(int i = 0; i < num;i++)
{
cin >> numberset[i];
}
sort(numberset, numberset + num);
for(int i = num - 1;i >= 2;i--)
{
if(numberset[i] < numberset[i-1] + numberset[i-2])
{
ans = numberset[i] + numberset[i-1] +numberset[i-2];
break;
}
}
cout << ans << endl;
return 0;
}
1.6.2 Ants
n只蚂蚁以每秒1cm的速度在长为Lcm的竿子上爬行。当蚂蚁爬到竿子的端点时就会掉落。由于竿子太细,两只蚂蚁相遇时,它们不能交错通过,只能各自反向爬回去。对于每只蚂蚁,我们知道它距离竿子左端的距离xi,但不知道它当前的朝向。请计算所有蚂蚁落下竿子所需的最短时间和最长时间。
1 <= L <= 10^6
1 <= n <= 10^6
0 <= xi <= L
O(2^n)穷竭搜索
枚举所有蚂蚁的初始朝向组合
O(n)
最短时间:所有蚂蚁都朝着最近的端点走
最长时间:视为穿过彼此身体 → 求蚂蚁到端点的最大距离
限制条件n <= 10
#include <iostream>
#include <algorithm>
using namespace std;
int L, //杆子长度
n; //蚂蚁只数
int a[100000];
int main()
{
cin >> L >> n;
for(int i = 0;i < n; i++)
{
cin >> a[i];
}
sort(a, a + n);
cout << "min = " << a[0];
cout << "max = " << a[n-1];
return 0;
}
这里有一个问题,题目输入给出的距离是针对左端点的。而我们的蚂蚁是可以双向移动的,所以如果用sort只是找到了距离左端点最近和最远的两只蚂蚁,但是如果他们可以往右走,结果完全可以不同。
#include <iostream>
#include <algorithm>
using namespace std;
int L, //杆子长度
n, //蚂蚁只数
maxans,
minans;
int a[100000];
int main()
{
cin >> L >> n;
for(int i = 0;i < n; i++)
{
cin >> a[i];
}
for(int i = 0;i < n; i++)
{
maxans = max(maxans, max(a[i], L - a[i]));
minans = max(minans, min(a[i], L - a[i]));
//minans = min(minans, min(a[i], L - a[i]));
//注意求min的时候外层应该取max,因为必须要最后一支蚂蚁走掉以后才算过程结束
}
cout << "min = " << minans;
cout << "max = " << maxans;
return 0;
}
1.6.3 难度增加的抽签问题
O(n^3logn) 内部[二分搜索]
(http://www.cnblogs.com/wkfvawl/p/9475939.html)
#include <iostream>
#include <algorithm>
using namespace std;
int numberset[1001] = {0};
int number, x, m, check;
int main()
{
//1 <= n <= 1000
cin >> number >> m;
for(int i = 0;i < number; i++)
{
cin >> numberset[i];
}
sort(numberset, numberset + number);
for(int i = 0;i < number; i++)
{
for(int j = 0;j < number; j++)
{
for(int k = 0;k < number; k++)
{
x = m - numberset[i] - numberset[j] - numberset[k];
if(binary_search(numberset, numberset + number, x))
{
check = 1;
break;
}
}
}
}
if(check == 0)
{
cout << "NO" << endl;
}
else
{
cout << "YES" << endl;
}
return 0;
}
O(n^2logn)
#include <iostream>
#include <algorithm>
using namespace std;
int numberset[1001] = {0},
sumset[1000001] = {0};
int number, x, m, check, index;
int main()
{
//1 <= n <= 1000
cin >> number >> m;
for(int i = 0;i < number; i++)
{
cin >> numberset[i];
}
for(int i = 0;i < number; i++)
{
for(int j = 0;j < number; j++)
{
sumset[index++] = numberset[i] + numberset[j]; //用set去重?但后面遍历会变麻烦?
//cout << sumset[index - 1] << "=" << numberset[i] << "+" << numberset[j] << endl;
//cout << index << endl;
}
}
sort(sumset, sumset + index);
for(int i = 0;i < number; i++)
{
for(int j = 0;j < number; j++)
{
x = m - numberset[i] - numberset[j];
if(binary_search(sumset, sumset + index, x))
{
check = 1;
break;
}
}
}
if(check == 0)
{
cout << "NO" << endl;
}
else
{
cout << "YES" << endl;
}
return 0;
}