宝箱Uva12325:
这道题很有思维强度,首先比较容易想到的是枚举宝箱的数量,从0到[n/s1]或者0到[n/s2]。但是由于输入很大,当s1,s2都很小的时候,那么枚举的数量将会非常的巨大。因此针对s1,s2较小而n很大的情况,需要提供另一种思路。
另一种枚举的思路是从s1,s2入手的。因为s1,s2很小,如果枚举的数量和他们成正相关,那么就可以确保枚举的效率。考虑一个事实:s1个宝物1和s2个宝物2是同样的体积,那么对于任意的宝物s1个宝物1和任意的s2个宝物2,我们总可以相互替换。只需要比较s2*v1与s1*v2的大小,就可以确定某一个宝物至多只能取s1-1或s2-1种,否则就可以相互替换。这样枚举的数量就限制在min(s1-1,s2-1,[N/s1],[N/s2])中了。
def solve(n,s1,v1,s2,v2):
max_v = 0
def recur_search(s1,v1,s2,v2):
nonlocal max_v
for k1 in range(0,n//s1+1):
remain = n-k1*s1
k2 = remain//s2
max_v = max(max_v,k1*v1+k2*v2)
def search_2(s,s1,v1,s2,v2):
nonlocal max_v
for k1 in range(0,s+1):
remain = n-k1*s1
k2 = remain//s2
max_v = max(max_v,k1*v1+k2*v2)
if n//s1<10000:recur_search(s1,v1,s2,v2)
elif n//s2<10000:recur_search(s2,v2,s1,v1)
elif s2*v11,s1,v1,s2,v2)
else:search_2(s1-1,s2,v2,s1,v1)
print(max_v)
Uva1374 使用IDA*算法效率会高一点。如果使用BFS效率将会非常低。对于队列,可能取元素和放元素比for循环要慢很多,其次,对于由于BFS很难进行剪枝,因为很多元素会重复计算,最后,判重的时候注意需要对状态进行排序,否则会造成状态的重复。但是排序,添加就需要很多的时间。
另外IDA*的一个好处是不需要在最后一次迭代中展开整个解答树。
(1) 尽量先拿两个较大的数先加再减,这样可以尽快接近目标。
(1) 总是使用最新得到的元素进行操作。
def solve(n):
def dfs(d,state):
nonlocal ok,max_d
if d==max_d:
if n in state:ok = True;
return
u = max(state)
if u<<(max_d-d)return
for op in [1,-1]:
for j in range(d,-1,-1):
next = state[d]+op*state[j]
if next<=0 or next in state:continue
if u>n and next>n:continue
state[d+1] = next
dfs(d+1,state)
if ok:return
max_d = 0
ok = False
for max_d in range(1,20):
ok = False
dfs(0,[1]+[0]*(max_d))
print(max_d)
if ok:print(max_d,);break
BFS的代码
def solve_3(n):
def bfs():
state = deque()
vsit = set()
vsit.add((1,))
state.append((1,))
while len(state[-1]):
now = state.popleft()
if n in now:return len(now)
for i in range(len(now)-1,-1,-1):
for op in [1,-1]:
next=tuple(sorted(now+(now[-1]+now[i]*op,)))
if next not in vsit and next[-1]>0 and next[-1] not in now:
vsit.add(next)
state.append(next)
print(bfs()-1)
Uva1603 这道题有一定难度,关键是要想到如何将正方形和边联系到一起。注意,我们以正方形作为搜索对象,然后将边存在正方形里面。我们将每一个可能的正方形都进行编号然后存储它们的边数,以及相关联的边(即时该正方形已经被去掉边了)。这样我们从小正方形开始,因为小正方形被破坏之后大的正方形也可能会被破坏掉,这样就减少许多节点。
(1) 如果我们将每一个正方形都动态的维护起来,那么编程上可能会比较繁琐,特别是在搜索时要维护正方形的状态。因此就干脆只维护固定的正方形,然后再判断该正方形是不是完全正方形。
(2) 可以进行剪枝,注意这样一个事实,如果当前的边里面最多的一个关联到x个正方形,那么后面的最理想的情况是每一次都可以减少x,则(maxd-d)*x
def solve(n,missing):
def row_match(x,y):
return (2*n+1)*x+y
def col_match(x,y):
return (2*n+1)*x+y+n
def init():
for v in missing:exists[v-1] = 0
remains,maxsize = 0,60
exists,matches = [1]*2*n*(n+1),[[] for i in range(2*n*(n+1))]
size,fullsize = [0]*maxsize,[0]*maxsize
contains = {}
s = 0
init()
for L in range(1,n+1):
for x in range(0,n-L+1):
for y in range(0,n-L+1):
contains[s] = set()
fullsize[s] = 4*L
for j in range(0,L):
up = row_match(x,y+j)
down = row_match(x+L,y+j)
left = col_match(x+j,y)
right = col_match(x+j,y+L)
e = [up,down,left,right]
for t in e:
contains[s].add(t)
matches[t].append(s)
size[s] += exists[up]+exists[down]+exists[left]+exists[right]
if size[s]==fullsize[s]:remains+=1
s+=1
def find_square():
for i in range(s):
if size[i]==fullsize[i]:return i
return -1
def process_edge():
for i,x in enumerate(matches):
num = 0
for squ in x:
if size[squ]==fullsize[squ]:num+=1
matches[i] = num
def dfs(d,remains):
nonlocal maxd,s,ok
if d==maxd:
if find_square()==-1:ok = True
return
most_destroyed = max(matches)
if (maxd-d)*most_destroyed < remains:return
k = find_square()
for edge in contains[k]:
for j in range(s):
if edge in contains[j]:
if size[j]==fullsize[j]:
remains -= 1
matches[edge]-=1
size[j] -= 1
dfs(d+1,remains)
if ok:return
for j in range(s):
if edge in contains[j]:
if size[j]==fullsize[j]:
remains +=1
matches[edge]+=1
size[j] += 1
ok = False
process_edge()
for maxd in range(1,n*n):
ok = False
dfs(0,remains)
print(maxd)
if ok:print(maxd);break
dfs法,相对来说效率会慢一些。因为第一次的搜索可能会搜到一个比较深的解,那么后来的优化剪枝就相对比较低效。
def solve(n,missing):
def row_match(x,y):
return (2*n+1)*x+y
def col_match(x,y):
return (2*n+1)*x+y+n
def init():
for v in missing:exists[v-1] = 0
remains,maxsize = 0,60
exists,matches = [1]*2*n*(n+1),[[] for i in range(2*n*(n+1))]
size,fullsize = [0]*maxsize,[0]*maxsize
contains = {}
s = 0
init()
for L in range(1,n+1):
for x in range(0,n-L+1):
for y in range(0,n-L+1):
contains[s] = set()
fullsize[s] = 4*L
for j in range(0,L):
up = row_match(x,y+j)
down = row_match(x+L,y+j)
left = col_match(x+j,y)
right = col_match(x+j,y+L)
e = [up,down,left,right]
for t in e:
contains[s].add(t)
matches[t].append(s)
size[s] += exists[up]+exists[down]+exists[left]+exists[right]
if size[s]==fullsize[s]:remains+=1
s+=1
def find_square():
for i in range(s):
if size[i]==fullsize[i]:return i
return -1
def process_edge():
for i,x in enumerate(matches):
num = 0
for squ in x:
if size[squ]==fullsize[squ]:num+=1
matches[i] = num
def dfs_1(d,remains):
nonlocal best
if d>= best:return
most_destroyed = max(matches)
if (best-d)*most_destroyed < remains:return
k = find_square()
if k==-1:best=d;print(best);return
for edge in contains[k]:
for j in range(s):
if edge in contains[j]:
if size[j]==fullsize[j]:
remains -= 1
matches[edge]-=1
size[j] -= 1
dfs_1(d+1,remains)
for j in range(s):
if edge in contains[j]:
size[j] += 1
if size[j]==fullsize[j]:
remains +=1
matches[edge]+=1
process_edge()
print(matches)
ok = False
best = n*n
dfs_1(0,remains)
print(best)