## 2018年12月1日土曜日

### Algorithm - Python - 招かれざる客(テーブルの中央と両端の席、重み、リストの連結、しらみつぶしの数え上げと符号化の組合わせ)

コード(Emacs)

Python 3

```#!/usr/bin/env python3

def get_two_guests(guests: list, dislike_pairs: list) -> list:
'''
>>> get_two_guests(large_guests, large_dislikes)
(['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'], ['A'])
'''
new_guests = []
other_guests = []
for guest in guests:
is_good = True
for dislike_pair in dislike_pairs:
if guest in dislike_pair:
is_good = False
if is_good:
other_guests.append(guest)
else:
new_guests.append(guest)
return new_guests, other_guests

def invite_dinner_flexible_optimized(guests: list, dislike_pairs: list) -> None:
'''
>>> invite_dinner_flexible_optimized(['A', 'B', 'C'], [('B', 'C')])
Optimum Solution: ['A', 'B', 'C']
>>> invite_dinner_flexible_optimized(['A', 'B', 'C'], [('A', 'B'), ('A', 'C')])
Optimum Solution: ['B', 'C']
>>> invite_dinner_flexible_optimized(['A', 'B', 'C'], [('A', 'B'), ('B', 'C')])
Optimum Solution: ['B', 'C']
>>> invite_dinner_flexible_optimized(['A', 'B', 'C'], [('A', 'C'), ('B', 'C')])
Optimum Solution: ['B', 'C']
'''
new_guests, other_guests = get_two_guests(guests, dislike_pairs)
n = len(new_guests)
invite = []
for i in range(2 ** n):
combination = []
num = i
for j in range(n):
if num % 2 == 1:
combination = [new_guests[n - 1 - j]] + combination
num //= 2
good = True
dislike_count = 0
for a, b in dislike_pairs:
if a in combination and b in combination:
dislike_count += 1
if dislike_count == 2:
good = False
break
if good and len(combination) > len(invite):
invite = combination
invite = other_guests + invite
print(f'Optimum Solution: {invite}')

def is_good(combination: list, name1: str, name2: str) -> bool:
names = [name for name, _ in combination]
return not (name1 in names and name2 in names)

def get_weight(combination: list) -> int:
return sum([weight for _, weight in combination])

def get_two_guests_weight(guests: list, dislike_pairs: list) -> list:
'''
>>> get_two_guests_weight(large_guests_weight, large_dislikes)
([('B', 1), ('C', 3), ('D', 2), ('E', 1), ('F', 4), ('G', 2), ('H', 1), ('I', 3)], [('A', 2)])
'''
new_guests = []
other_guests = []
for guest in guests:
is_good = True
for dislike_pair in dislike_pairs:
if guest[0] in dislike_pair:
is_good = False
break
if is_good:
other_guests.append(guest)
else:
new_guests.append(guest)
return new_guests, other_guests

def invite_dinner_flexible_weight_optimized(
guests: list, dislike_pairs: list) -> None:
'''重み付き最適化した版
>>> invite_dinner_flexible_weight_optimized(large_guests_weight, large_dislikes)
Optimum Solution: [('A', 2), ('C', 3), ('E', 1), ('F', 4), ('I', 3)]
Weight is: 13
'''
new_guests, other_guests = get_two_guests_weight(guests, dislike_pairs)
n = len(new_guests)
invite = []
invite_weight = 0
for i in range(2 ** n):
num = i
combination = []
for j in range(n):
if num % 2 == 1:
combination = [new_guests[n - 1 - j]] + combination
num //= 2
good = True
dislike_count = 0
for a, b in dislike_pairs:
if not is_good(combination, a, b):
dislike_count += 1
if dislike_count == 2:
good = False
break
if good:
weight = get_weight(combination)
if weight > invite_weight:
invite = combination
invite_weight = weight
invite = other_guests + invite
invite_weight += get_weight(other_guests)
print(f'Optimum Solution: {invite}')
print(f'Weight is: {invite_weight}')

if __name__ == '__main__':
import doctest
globs = locals()
large_dislikes = [['B', 'C'], ['C', 'D'], ['D', 'E'],
['F', 'G'], ['F', 'H'], ['F', 'I'], ['G', 'H']]
large_guests = [chr(ord('A') + i) for i in range(9)]
large_guests_weight = list(zip(large_guests, [2, 1, 3, 2, 1, 4, 2, 1, 3]))
globs.update({'large_dislikes': large_dislikes,
'large_guests': large_guests,
'large_guests_weight': large_guests_weight})
doctest.testmod(globs=globs)
invite_dinner_flexible_optimized(large_guests, large_dislikes)
```

```\$ ./sample3.py -v
Trying:
get_two_guests(large_guests, large_dislikes)
Expecting:
(['B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'], ['A'])
ok
Trying:
get_two_guests_weight(large_guests_weight, large_dislikes)
Expecting:
([('B', 1), ('C', 3), ('D', 2), ('E', 1), ('F', 4), ('G', 2), ('H', 1), ('I', 3)], [('A', 2)])
ok
Trying:
invite_dinner_flexible_optimized(['A', 'B', 'C'], [('B', 'C')])
Expecting:
Optimum Solution: ['A', 'B', 'C']
ok
Trying:
invite_dinner_flexible_optimized(['A', 'B', 'C'], [('A', 'B'), ('A', 'C')])
Expecting:
Optimum Solution: ['B', 'C']
ok
Trying:
invite_dinner_flexible_optimized(['A', 'B', 'C'], [('A', 'B'), ('B', 'C')])
Expecting:
Optimum Solution: ['B', 'C']
ok
Trying:
invite_dinner_flexible_optimized(['A', 'B', 'C'], [('A', 'C'), ('B', 'C')])
Expecting:
Optimum Solution: ['B', 'C']
ok
Trying:
invite_dinner_flexible_weight_optimized(large_guests_weight, large_dislikes)
Expecting:
Optimum Solution: [('A', 2), ('C', 3), ('E', 1), ('F', 4), ('I', 3)]
Weight is: 13
ok
__main__
__main__.get_weight
__main__.is_good
4 items passed all tests:
1 tests in __main__.get_two_guests
1 tests in __main__.get_two_guests_weight
4 tests in __main__.invite_dinner_flexible_optimized
1 tests in __main__.invite_dinner_flexible_weight_optimized
7 tests in 7 items.
7 passed and 0 failed.
Test passed.
Optimum Solution: ['A', 'C', 'E', 'G', 'H', 'I']
\$
```