您的位置:首页 > 编程语言 > Go语言

Google APAC test 2015 Round B Problem C - Card Game

2014-09-16 13:07 267 查看
源题地址:
https://code.google.com/codejam/contest/4214486/dashboard#s=p2
题意:

给定一个无序数组cards[]和数字k,如果存在连续的三个数a,b,c有如下关系:

c-b = b-a = k

那么就把这三个数删除,重复这个过程,直到不存在这样的关系,问怎样删才能使得最终剩下来的数的个数最少?最少为多少

分析:

使用区间dp方法, 建一个图有向图(准确的说是一个拓扑图),从图中找出一条最短路径

1)建图

图的节点表示每个字符,边(i,j)表示card[j] 是否可能成为card[i]的下一个数组(中间可能经过多次删除)。下图中以k=0为例子,



这样的i、j存在一个这样的关系 j = (i+1) + 3*D, 其中D表示其中删除的次数,为了缩减空间可以将图的空间申请如下:

bool dp[cards.size()/3+1][cards.size()+2]

为了便于递归,在card数组的最前面加入一个head表示起点(因为第一个数可能被删除),在最后面插入tail:

dp[i][j] = True 表示 cards[i*3+j+1]在经过多次删除后能够成为cards[j] 的下一个节点,那么递推关系是

dp[i+1][j]  = dp[i+1][j] || ( dp[p][j] && dp[q][j+p*3+1] && dp[r][j+(p+q)*3+2) && dp[i-1-(p+q+r)]   )     ( 0 <= p, q, r, (i-1-p-q-r) <= i-1)

上图中对应的dp数组生成如下:



实现的时候,需要五重循环,所以时间复杂度最高是O(N^5),  大数据最终2.5s运行完毕。

2)从图中找到最短的的路径head到tail的最短路径

也是用dp的思路,用length[i]表示保留card[i],从head出发到达card[i]的最短长度

length[i] = min(length[j]+1)       (0 <= j < i, j是i所有可能的前驱)

最终的结果是head到tail的路径长度-1

代码:

def minCards(cards, k):

cards.insert(0, 0)

dp = [ [ False for i in range(0,len(cards)+1) ] for j in range(0, len(cards)/3+1) ]

for j in range(0, len(cards)+1):

dp[0][j] = True

for i in range(1, len(cards)/3+1):

for j in range(0, len(cards)+1):

if j + i*3 < len(cards):

for p in range(0, i):

if dp[i][j] == True:

break;

if dp[p][j]:

for q in range(0, i-p):

if dp[q][j+3*p+1]:

for r in range(0, i-(p+q)):

if dp[r][j+3*(p+q)+2] and dp[i-1-p-q-r][j+3*(p+q+r)+3] and cards[j+3*p+1]+k == cards[j+3*(p+q)+2] and cards[j+3*(p+q)+2]+k == cards[j+3*(p+q+r)+3]:

dp[i][j] = True

length = range(0, len(cards)+2)

for i in range(0, len(cards)+1):

for j in range(0, len(cards)/3+1):

if  j*3+i < len(cards)+2:

if dp[j][i] and length[j*3+i+1] > length[i]+1:

length[j*3+i+1] = length[i]+1

return length[len(cards)]-1

fin = open('c_large.in','r')

fout = open('c_large.out','w')

line = fin.readline()

n = int(line)

for i in range(0,n):

    line = fin.readline()

    line = line.split(' ')

    k = int(line[1])

    line = fin.readline()

    line = line.split(' ')

    cards = [int(j) for j in line]

    res = minCards(cards, k)
    fout.write("Case #%d: %s\n"%(i+1, res))

fin.close()

fout.close()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息