题目地址:点击打开链接
思路:对于此题,求三个数n1,n2,n3使其之和为另一个数字n。如果存在多种情况,求n值最大的一个。所以首先将所有的数字从小到大排列,从后向前求解,这样就保证求得的第一个赢家为最大值。另外三个数就需要枚举了。三个赌徒,至少有一个在赢家(i)的前面(j),但是由于存在负数,所以另外两个赌徒的编号就有可能在赢家的后面,最初考虑这题的时候,忽略了这点(如果没有负数,三个赌徒肯定都在赢家的前面了)。另外就是如果三个数都要考枚举的话,算法复杂度为O(n^4)。但是由于前面已经对数组进行排序,所以可以先枚举其中两个(j,k),则第三个赌徒的赌注为tmp = jetton[i] – jetton[j] – jetton[k]; 然后进行二分查找tmp,如果存在,则结束枚举就行了,这样可以降低算法复杂度,不过仍为O(n^3lgn)
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int a[101000],n,winner;
int bsearch(int begin1,int goal)
{
int left = begin1 + 1,right = n - 1,mid;
while(left <= right)
{
mid = (left + right) / 2;
if(a[mid] == goal)
return mid;
else if(a[mid] < goal)
left = mid + 1;//注意分号敲错
else
right = mid - 1;
}
return 0;
}
int solve()
{
int i,j,k,other,location;
for(i=n-1; i>=0; i--)
{
for(j=i-1; j>=0; j--)//最小的那个数一定比i小
{
for(k=j+1; k < n; k++)//次小的数一定比最小的数大,但不知道和i的大小关系,因为有负数的存在
{
other = a[i] - a[j] - a[k];
location = bsearch(k,other);
if(location && location != i)
{
winner = i;
return 1;
}
}
}
}
return 0;
}
int main()
{
int i;
while(scanf("%d",&n) && n)
{
for(i=0; i<n; i++)
{
scanf("%d",&a[i]);
}
sort(a,a+n);
if(solve())//for循环写成一个函数这样就可以一次退出
printf("%d\n",a[winner]);
else
printf("no solution\n");
}
return 0;
}