算法竞赛入门第五章(竞赛题目选讲)解析:

46 篇文章 0 订阅

例题5-8,此题不难,关键在于将files排序后能够找到对应的列数和行数(行数要小心n是cols倍数的特殊情况,所以要用n-1去除),然后按行输出。因为是列优先,所以索引的求解变成j*rols+i。

def format_files(files):
    M = len(max(files,key = lambda x:len(x)))
    def Print(s,extra):
        print(s,end='')
        print(extra*' ',end ='')
    maxclos = 60
    n = len(files)
    cols = (maxclos - M)//(M+2) + 1
    rows = n//cols + 1
    print(cols,rows,M)
    files.sort()
    for i in range(rows):
        for j in range(cols):
            index = j*rows + i
            if(index < n):
                if (j == cols-1):Print(files[index],M-len(files[index]))
                else:Print(files[index],M+2-len(files[index]))
        print('')
format_files(['Alice','Bobby','Buffy','Carol','Chris','Jan','Ruben','Peter','Sissy'])

例题5-9:此题同样不难,关键在于使用字典进行查询。当然这里有一个优化的重要技巧:预处理。因为进行字符串的比较是很慢的,所以我们可以先队字符串进行编号,这样数据库表就变成关于整数的表,这样比较的时候就快的多。

同样注意,我们的程序最多可能经历三重循环(当然大多数时候只有两重),所以预处理的两重循环对程序是由提升的,如果都是两重循环,就没有必要进行预处理了!

def search_same_rowcol(data,m,n):
    CharsetCache = {}
    def pre_process():#预处理
        kase = 0
        for i in range(m):
            for j in range(n):
                s = data[i][j]
                if s in CharsetCache:data[i][j] = CharsetCache[s]
                else:
                    CharsetCache[s] = kase
                    data[i][j] = kase
                    kase += 1
    def test(r1,r2,col_start):
        for j in range(col_start+1,n):
            if data[r1][j] == data[r2][j]:
                print((r1+1,r2+1),(col_start+1,j+1))
                return True
        return False
    pre_process()
    for j in range(n):
        rec = {}
        for i in range(m):#按列进行遍历
            if data[i][j] not in rec:
                rec[data[i][j]] = i
            else:#找到一样的元素
                x = test(rec[data[i][j]],i,j)
                if x : print(data);return
search_same_rowcol([['How to Compete in ACM ICPC','Peter','peter@aaa'],\
['How to win in ACM','Michael','michael'],['How to from','Michael','michael']],3,3)

例题5-11:本题同样不难,但是比较考验细节的处理。可以锻炼代码的组织能力。注意我将几个功能进行模块化,之后分别处理.先处理所有mta,然后处理收件人的顺序,最后进行格式化的输出。

from collections import namedtuple
user =  namedtuple('user',['username','mtaname'])
MTA_Cache = {}#{'name':{user1,user2...}}
def get_user(s):
    info = s.split('@')
    return user(info[0],info[1])
def receive_mta():
    msg = input()
    while(msg!='*'):
        msg = msg.split(' ')
        MTA_Cache[msg[1]] = set()
        for user in msg[3:]:
            MTA_Cache[msg[1]].add(user)
        msg = input()
def process_recv(indentifier):
    indentifier = indentifier.split(' ')
    sender = get_user(indentifier[0])
    recipients = set()
    indentifier = indentifier[1:]#去掉sender的信息
    while(indentifier[0]!='*'):
        for each_user in indentifier:
            recipients.add(get_user(each_user))
        indentifier = input()
        indentifier = indentifier.split(' ')
    return sender,recipients
def get_data():
    temp_data = input()
    data = ''
    while(temp_data!='*'):
        data += (temp_data+'\n')
        temp_data = input()
    return data+'.'
def do_sort(recipients):
    mta_cache = []
    recipients_cache = {}
    for each_recipient in recipients:
        mtaname = each_recipient.mtaname
        username = each_recipient.username
        if mtaname in recipients_cache:
            recipients_cache[mtaname].append(username)
        else:
            mta_cache.append(mtaname)
            recipients_cache[each_recipient.mtaname] = [username]
    return mta_cache,recipients_cache
def format_print(sender,rec_mta,recipients_queue,data):
    def format_user(user):
        return '<'+user.username+'@'+user.mtaname+'>'
    print('connection between',sender.mtaname,'and',rec_mta)
    print('HELO',sender.mtaname)
    print('Mail From :'+format_user(sender)+'\n250')
    ok = False
    for recipient in recipients_queue:
        print('RCPT To :'+format_user(user(rec_mta,recipient)))
        if recipient in MTA_Cache[rec_mta]:
            ok = True
            print('250')
        else :print('550')
    if ok:print('DATA\n354\n'+data)

def process_sessions():
    receive_mta()
    while(1):
        end_or_recv = input()
        if (end_or_recv=='*'):break
        else:sender,recipients = process_recv(end_or_recv)
        data = get_data()
        sorted_mtas,sorted_recipients = do_sort(recipients)
        for each_mta in sorted_mtas:
            recipients_queue = sorted_recipients[each_mta]
            format_print(sender,each_mta,recipients_queue,data)
        print('QUIT\n221')
process_sessions()

例题5-12:这道题一开始没有想出来,后来看了书上的分析做出来了。最关键的一点就是将x坐标作为区间来处理。注意不是以建筑为基本单位的。只要想到这一点就不难了。这道题最重要的是离散化的思想,而且要选择正确的离散化方式!!!以后碰到这种类型其实就不难想到了。离正确的思路只有一步之遥!

思路:就是将x进行去重处理后排序,获取所有区间。然后就可以将一个区间当作一个点处理(取中点即可)。判断一个建筑是否可以看见的关键在于:有没有一个它所在的区间能没有任何在它前面的建筑会挡住它!
from collections import namedtuple
building = namedtuple('building',['x','y','width','depth','height','index'])
building_cache = []
X_cache = set()
def process_input():
    global X_cache
    kase = 0
    while(1):
        x = input()
        if x == '0':break
        kase += 1
        x = x.split(' ')
        x = [int(each) for each in x]
        b = building(x[0],x[1],x[2],x[3],x[4],kase)
        X_cache.add(b.x)
        X_cache.add(b.x+b.width)
        building_cache.append(b)
    X_cache = list(X_cache)
    X_cache.sort()
    building_cache.sort(key = lambda x:x.y)
    building_cache.sort(key = lambda x:x.x)
def isvisible(b):
    flag = False
    for i in range(len(X_cache)-1):
        left,right = X_cache[i],X_cache[i+1]
        mid = (left+right)/2
        if covert(b,mid):
            s = [1 for each in building_cache if covert(each,mid) and each.y < b.y and each.height >= b.height]
            if(s == []):flag = True#可以看见
    return flag
def covert(b,mid):
    if b.x <= mid and b.x + b.width>= mid:
        return True
    else:return False
def Process():
    process_input()
    for i,building in enumerate(building_cache):
        if isvisible(building):
            print(building.index,end = ' ')
Process()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值