https://www.icourse163.org/learn/PKU-1001894005?tid=1450413466#/learn/content
程序设计与算法(二)算法基础
4143:和为给定数
# 4143:和为给定数
# http://bailian.openjudge.cn/practice/4143
# 二分查找的目标是对于有序列表,在其中寻找指定的目标元素的位置。
def BinarySearch(L, target):
left = 0
right = len(L) - 1
while (left <= right):
mid = left + (right - left) // 2 # 为了防止(L+ R)过大溢出
if (L[mid] == target): # 如果中间位置的元素 == target,那么查找成功
return mid
elif (L[mid] < target): # 如果中间位置的元素 < target,那么左端点设置为中间+1
left = mid + 1
else: # 如果中间位置的元素 > target,那么右端点设置为中间-1
right = mid - 1
return 'TARGET_NOT_FOUND'
num_int = int(input()) # 第一行是整数n(0 < n <= 100,000),表示有n个整数。
int_list = input().split() # 第二行是n个整数。整数的范围是在0到10^8之间。
for i in range(0, len(int_list)):
int_list[i] = int(int_list[i])
sumsum = int(input()) # 第三行是一个整数m(0 <= m <= 2^30),表示需要得到的和。
# 方法1:排序 + 二分查找
# 1)将数组排序,复杂度是O(n*log(n))
# 2)对数组中的每个元素a[i],在数组中二分查找m-a[i],看能否找到。
# 复杂度log(n), 最坏要查找n-2次,
# 所以查找这部分的复杂度也是O(n*log(n))
# 这种解法总的复杂度是O(n*log(n))的。
int_list.sort()
for ii in range(0, num_int):
ind = BinarySearch(int_list, sumsum - int_list[ii])
if ind != 'TARGET_NOT_FOUND':
print('%d %d' % (int_list[ii], int_list[ind]))
break
if ind == 'TARGET_NOT_FOUND':
print('No')
# 4143:和为给定数
# http://bailian.openjudge.cn/practice/4143
num_int = int(input()) # 第一行是整数n(0 < n <= 100,000),表示有n个整数。
int_list = input().split() # 第二行是n个整数。整数的范围是在0到10^8之间。
for i in range(0, len(int_list)):
int_list[i] = int(int_list[i])
sumsum = int(input()) # 第三行是一个整数m(0 <= m <= 2^30),表示需要得到的和。
# 方法2:排序 + 查找
# 1)将数组排序,复杂度是O(n*log(n))
# 2)查找的时候,设置两个变量i和j,i初值是0,j初值是n-1
# 如果a[i]+a[j]大于m,就让j减1
# 如果a[i]+a[j]小于m,就让加1
# 直至a[i]+a[j]=m。
# 这种解法总的复杂度是O(n*log(n))的。
int_list.sort()
left = 0
right = num_int - 1
while left != right:
if int_list[left] + int_list[right] > sumsum:
right -= 1
elif int_list[left] + int_list[right] < sumsum:
left += 1
else:
print('%d %d' % (int_list[left], int_list[right]))
break
if left == right:
print('No')
2456:Aggressive cows 疯牛
# 2456:Aggressive cows
# http://bailian.openjudge.cn/practice/2456
# 判断能否以距离mid将C头牛全部分配到房间列表room_list中
def Check(mid, room_list, C):
count = 1
temp = room_list[0] # 将第一头牛分配给房间列表的第0个房间
for ii in range(1, len(room_list)): # 从最小编号的隔间开始分配房间
if room_list[ii] - temp >= mid: # 如果第ii个房间与房间temp的距离 >= mid
count += 1 # 对已经分配了的牛进行计数
temp = room_list[ii] # 分配第ii个房间
if count >= C: # 如果分配完了C头牛
return True
return False
# (2)二分查找 在L中求满足Check(mid, L, C)的最大的距离mid
# 在[L,R]内用二分法尝试“最大最近距离”mid = (L+ R)/2 (L,R初值为[1, 1,000,000,000/C]
# 复杂度log(1,000,000,000/C) * N
def BinarySearch(room_list, C):
left = 0 #最小距离
right = room_list[-1] - room_list[0] # 最大距离
while (left <= right): # 最后一次循环结束后,left = right + 1
mid = left + (right - left) // 2 # 为了防止(L+ R)过大溢出
if Check(mid, room_list, C): # 若mid可行,则记住该mid,然后在新[L,R]中继续尝试(L= mid+1)
left = mid + 1
else: # 若mid不可行,则在新[L, R]中继续尝试(R= mid-1)
right = mid - 1
# 若最后一次循环中mid满足条件,则left = mid + 1 = right + 1,最大的满足条件的应该是mid = left-1
# 若最后一次循环中mid不满足条件,则right = mid - 1 = left - 1,最大的满足条件的应该是mid-1 =left-1
return left - 1
room_list = input().split() # 第1行:空格分隔的两个整数N和C。
N = int(room_list[0]) # N个隔间 N == len(room_list)
C = int(room_list[1]) # C头牛
room_list = []
for ii in range(0, N): # 第2~N+1行:分别指出xi的位置。
room_list.append(int(input()))
room_list.sort() # 对隔间的编号由小到大排序
print("%d" % BinarySearch(room_list, C))