此问题出现在USACO 2016年2月竞赛,青铜赛区(问题3)
Farmer John的NN奶牛各自站在不同的位置 (x1,y1)...(xn,yn)在他的二维农场(1≤N≤100),以及 xi和yi是大小最大的正奇数整数B)。 FJ想要 通过建立一个长的(有效的 无限长的)南北栅栏,方程式x = a(a将是一个 甚至整数,从而确保他不会通过建立围栏 任何牛的位置)。他也想建立一个长期(有效 无限长度)东西方围栏,方程y = b,其中b是偶数 整数。这两个围栏在点(a,b)交叉,并且它们在一起 将他的领域划分为四个区域。
FJ想要选择a和b以便让奶牛出现在四只奶牛中 产生的区域合理地“平衡”,没有区域包含 太多的奶牛。设M是出现的最大奶牛数 作为四个地区中的一个,FJ希望M尽可能小。 请帮助他确定M的最小可能值。
对于前五个测试用例,B保证最多为100个 所有测试用例,B保证最多为1,000,000。
我使用暴力算法使前5个测试用例正确运行,大约在O(n ^ 2)时间内运行,但很明显,如果B是一个大数字,这将无法解决。
然后我尝试通过将两个栅栏放在数据点的中间位置附近来减少解决方案的时间,但这似乎不起作用。
以下代码:
fin = open('balancing.in', 'r');
fout = open('balancing.out', 'w');
xcows = [];
ycows = []
mincows = 10000;
N, B = map(int, fin.readline().split());
for i in range(N):
x1, y1 = map(int, fin.readline().split());
xcows.append(x1);
ycows.append(y1);
xlow,ylow,xhigh,yhigh = 0,0,0,0;
xmedian = -1;
xxcows = sorted(xcows)
yycows = sorted(ycows)
if len(xxcows)%2==0:
med = len(xxcows)//2;
xmedian = int(xxcows[med] + xxcows[med-1])//2;
else:
med = len(xxcows)//2;
xmedian = xxcows[med];
xlow = (xmedian//2)-1;
xhigh = (xmedian//2)+1;
ymedian = -1;
if len(yycows)%2==0:
med = len(yycows)//2;
ymedian = int(yycows[med] + yycows[med-1])//2;
else:
med = len(yycows)//2;
ymedian = yycows[med];
ylow = (ymedian//2)-1;
yhigh = (ymedian//2)+1;
for xx in range(xlow-1, xhigh+2):
for yy in range(ylow-1, yhigh+2):
#place boundary at x = xx and y = yy and count cows in each quadrant
q1, q2, q3, q4 = 0, 0, 0, 0;
for q in range(len(xcows)):
if xcows[q] < xx*2 and ycows[q] > yy*2:
q1+=1;
elif xcows[q] > xx*2 and ycows[q] > yy*2:
q2+=1;
elif xcows[q] < xx*2 and ycows[q] < yy*2:
q3+=1;
elif xcows[q] > xx*2 and ycows[q] < yy*2:
q4+=1;
mini = max(q1, q2, q3, q4);
if mincows > mini:
mincows = mini;
fout.write(str(mincows));
fin.close();
fout.close();
此代码只有2/10个测试用例正确无误。我不明白为什么这个算法不起作用。如果有更好的算法,请随意分享,因为我很难过。
答案 0 :(得分:1)
解决方案不依赖于B的大小,只取决于奶牛的数量N.对于每个xi尝试将NS线作为xi - 1.对于每个yi,尝试将EW线放在yi - 1处。因为最多有100头奶牛,所以最多可以尝试10000箱。
<div id="sb-search" class="sb-search">
<form action="<?php echo get_bloginfo('url'); ?>">
<input class="sb-search-input" placeholder="Enter your search term..." type="search" value="" name="search" id="search">
<input class="sb-search-submit" type="submit" value="">
<span class="sb-icon-search"></span>
</form>
</div>
答案 1 :(得分:0)
对于大量奶牛,需要更好的搜索策略。以下程序从最初的猜测开始,并尝试将围栏移动到东西,南北和对角线的下一个位置,以查看它是否提高了分数。保留与当前最佳分数匹配的任何围栏位置的队列。答案是当队列为空时当前的最佳得分和位置。
取消注释打印语句以查看其工作原理。
from collections import deque
def calc_score(ew_fence, ns_fence):
cnts = [0,0,0,0]
for cow in cows:
i = (0 if cow[1] < ew_fence else 2) + (0 if cow[0] < ns_fence else 1)
cnts[i] += 1
return max(cnts)
def solve2(cows):
xs,ys = zip(*cows)
xs = sorted(x-1 for x in set(xs))
ix = len(xs)//2
ys = sorted(y-1 for y in set(ys))
iy = len(ys)//2
#print("Initial score = {} at ix,iy = ({},{})".format(calc_score(xs[ix],ys[iy]), ix, iy))
seen = set([(ix, iy)])
queue = deque([(ix, iy)])
best_score, best_ix, best_iy = calc_score(xs[ix],ys[iy]), ix, iy
while queue:
ix, iy = queue.pop()
#print("checking near: ix,iy = ({}, {})".format(ix, iy))
for dx,dy in ((-1, 1), (0, 1), (1, 1),
(-1, 0), (1, 0),
(-1,-1), (0,-1), (1,-1)):
nx, ny = ix + dx, iy + dy
if (nx,ny) in seen:
#print("\t({},{}) - seen".format(nx, ny))
continue
seen.add((nx, ny))
score = calc_score(xs[nx], ys[ny])
if score < best_score:
best_score, best_ix, best_iy = score, nx, ny
#print("\t({},{}) - new best score = {}".format(best_ix, best_iy, best_score))
queue.clear()
if score == best_score:
queue.append((nx, ny))
#print("\t({},{}) = enqueue".format(nx, ny))
#print("\nbest score = {} at ix,iy = ({},{}) = grid coords ({},{})".format(
# best_score, best_ix, best_iy, xs[best_ix], ys[best_iy]))
return best_score, (xs[best_ix], ys[best_iy])