30歳で競プロに目覚めた霊長類のブログ

ウホウホ (競プロの世界にやってきました。がんばります。)

Atcoder Beginner Contest 075

5日ぐらい前のやつです。

結果

A,B,Cの3完。タイム23:33。302位。
レート変動なし。

感想

水色コーダーになってから初めてのABC。
これから青コーダーを目指すにあたってサクッと全完する... つもりが、
D問題で迷宮に陥り、時間切れ。
精進しなきゃ。。

A One out of Three

A - One out of Three

素直にif-elseする問題。(説明になってない)

A,B,C = map(int,input().split())
if A == B: print(C)
elif B == C: print(A)
else: print(B)

すごいと思ったのが、if文を使わずにXOR演算で print(A^B^C) みたいに解いた人がいたらしい。
確かに、同じ数を偶数回XORするとその数は消えるから、答えが残るね。
絶対に思いつかないな〜。

B Minesweeper

B - Minesweeper

いわゆるマインスイーパの爆弾の位置が与えられて、空きマスについて、8近傍に爆弾がいくつあるかを求める問題。

これも基本的なif-elseとfor文が使えればできそう。
でもABCのBにしては実装量が少し多い。

H,W = map(int,input().split())
src = [input() for i in range(H)]
 
ans = []
for row in src:
    ans.append(list(row))
 
dxy = [(-1,-1),(-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1)]
for y in range(H):
    for x in range(W):
        if src[y][x] == '#': continue
        c = 0
        for dx,dy in dxy:
            if x+dx < 0 or x+dx > W-1 or y+dy < 0 or y+dy > H-1: continue
            if src[y+dy][x+dx] == '#': c += 1
        ans[y][x] = c
 
for row in ans:
    print(''.join(list(map(str,row))))

2行目のsrcに文字列の配列を読み込んでいるけど、
Pythonだとsrc[0][1] = '1'みたいな文字列への代入ができなくて、
仕方なく答えを書き出す用のansという配列の配列を用意してる。
最終的にansを結合して出力してる。(なんか微妙な気が。。

あとは、8近傍の調べ方がいくつかテクがあるっぽい。
解説のソースコードを抜粋すると、↓の書き方だった。

const int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
const int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};

でもこれ、うまく説明できないけど、なんかモヤっとする...。
dx[i]dy[i]はセットで意味をなすので、(dx[i],dy[i])みたいにまとめたいと思ってしまう。

というわけで、せめてもの抵抗として(笑) (dx[i],dy[i])とタプルでまとめたコードを貼り付けた。
でも、カッコで囲ってるぶん、タイプ数が少し多いような。
競プロは早さを競うのだからうだうだ言ってられませんがな。

次からは素直にdxdyでやるか。(ズコー

ちなみに、上で載せた私のコードは実はブログ用に書き直してて、本番でAC取ったのは愚直なif-elseの山。

(おまけ)ACは取ったけど載せるのをためらったコードは↓
Submission #1682548 - AtCoder Beginner Contest 075

C Bridge

C - Bridge

二重辺や自己ループのない無向連結グラフがあって、取り除いたら連結じゃなくなる辺がいくつあるか。
以下私の回答。

N,M = map(int,input().split())
es = []
for i in range(M):
    a,b = map(int,input().split())
    a,b = a-1, b-1
    es.append((a,b))
 
parent = None
def root(a):
    if parent[a] == a:
        return a
    else:
        parent[a] = root(parent[a])
        return parent[a]
def is_same(a,b):
    return root(a) == root(b)
def unite(a,b):
    ra = root(a)
    rb = root(b)
    if ra == rb: return
    parent[ra] = rb;
 
ans = 0
for i in range(M):
    parent = [k for k in range(N)]
    for j,e in enumerate(es):
        if j == i: continue
        a,b = e
        unite(a,b)
    a,b = es[i]
    if not is_same(a,b):
        ans += 1
print(ans)

Union-Findを使って解いた。
Union-Findは、競プロ歴5ヶ月の私が知ってる知識をざっくり説明すると、

  • グラフのある頂点とある頂点が繋がってるかどうか高速に判定するよ
  • 辺がない状態から、辺を追加しながら構築するよ。構築の途中でも判定できるよ
  • 判定も追加もほぼ定数時間(ちょうはやい)。アッカーマン関数(とてもでかい)の逆数だとか
  • 初期化するのだけO(N)かかるよ(N:頂点数)

上記コード中に出てきたroot()is_same()unite()がUnion-Findだけど、
スニペットに入れてたやつそのままなのでかなり楽できた。

あとは、全ての辺をループして、辺eを除いたグラフでUnion-Findを構築して、
辺eの両端が繋がってるかを判定していけばいい。

計算量は、辺ごとにUnion-Find初期化+構築でO(N+M)なので全体でO(M(N+M))かな?
NもMも小さいので大丈夫!

ちなみに、想定解ではUnion-FindじゃなくてDFSで解いてたみたい。
DFSは思いつかなかったので両方思いつくようになりたい。

2部グラフ判定問題

先日のコドフェで、2部グラフってのを扱う問題が出たので、勉強してみた。

2部グラフとは

(雑な説明、ご容赦ください)
いくつかの頂点があって、それらを辺で繋いで考えるモデルをグラフという。
棒グラフとか、円グラフとか、折れ線グラフとかのグラフではなくて、グラフ理論のはなし。

グラフ理論のグラフにも種類があって、2部グラフはその中の1つ。
どんな特徴があるかというと、頂点を2つのチームに分けたとき、「全ての辺が、自分チームと相手チームを結んでいる」ように分けることができる。

  • 2部グラフの例
    f:id:prd_xxx:20171020010001p:plain

  • 2部グラフじゃない例
    f:id:prd_xxx:20171020010013p:plain

例えば、男女の複雑な三角関係や四角関係(!?) を図に書いたとき、男女間でしか線が引かれていなければ2部グラフと言える。
男男間、女女間にも線が引かれていれば、2部グラフじゃないかもしれない。
かもしれないと言ったのは、別の何かしらの基準で(例えば右利きの人と左利きの人みたいに)チーム分けしたときに、「全ての辺が、自分チームと相手チームを結んでいる」ふうにできれば、2部グラフだから。

よく考えたら、三角関係が含まれていたら、2部グラフになり得ないっすね。^^;

2部グラフ判定問題の解き方

2部グラフ判定問題とは、与えられたグラフが2部グラフかどうか、という問題である。
「蟻本」の94ページに、C++のコードが載っていたので、意訳してpythonで書いてみた。

全ての辺において、一方が黒、もう一方が白となるように頂点を塗ることを考える。
2部グラフの場合、ある頂点の色が黒だとすると、そこに隣接している頂点は一意に白と決まる。
最初は適当に1箇所を黒で塗って、あとはDFS(深さ優先探索)で白、黒、白... とどんどん塗っていって、矛盾がなければ2部グラフ。

難しそうに思えて、意外と単純!

# 再帰の深さが1000を超えそうなときはこれをやっておく
import sys
sys.setrecursionlimit(10**7)

# 入力のつもり。esはよくある隣接リストで辺を表したもの。
N = 5
#es = [[1,2,3],[0,2],[0,1],[0,4],[3]] # False
es = [[1,3],[0,2],[1,3],[0,2,4],[3]] # True

#n個の頂点の色を初期化。0:未着色、1:黒、-1:白
colors = [0 for i in range(N)] 

#頂点vをcolor(1 or -1)で塗り、再帰的に矛盾がないか調べる。矛盾があればFalse
def dfs(v,color):
    #今いる点を着色
    colors[v] = color
    #今の頂点から行けるところをチェック
    for to in es[v]:
        #同じ色が隣接してしまったらFalse
        if colors[to] == color:
            return False
        #未着色の頂点があったら反転した色を指定し、再帰的に調べる
        if colors[to] == 0 and not dfs(to, -color):
            return False
    #調べ終わったら矛盾がないのでTrue
    return True

#2部グラフならTrue, そうでなければFalse
def is_bipartite():
    return dfs(0,1) # 頂点0を黒(1)で塗ってDFS開始

print(is_bipartite())

ちなみに、2部グラフは英語では、bipartite graph というみたい。
biは"2"、partiteは "partに分ける"ってことかな?(適当)
is_nibu() とかでもいいんだけど、なんかダサかったので(笑)

おまけで、再帰なし版も載せておきます。

# 入力のつもり。esはよくある隣接リストで辺を表したもの。
N = 5
#es = [[1,2,3],[0,2],[0,1],[0,4],[3]] # False
es = [[1,3],[0,2],[1,3],[0,2,4],[3]] # True

#n個の頂点の色を初期化。0:未着色、1:黒、-1:白
colors = [0 for i in range(N)]

#2部グラフならTrue, そうでなければFalse
def is_bipartite():
    stack = [(0,1)] # (頂点、色)のタプルをスタックする。最初は(頂点0, 黒(1))
    while stack:
        #スタックから最後に追加された(頂点, 色)をpop
        v,color = stack.pop()
        #今いる点を着色
        colors[v] = color
        #今の頂点から行けるところをチェック
        for to in es[v]:
            #同じ色が隣接してしまったらFalse
            if colors[to] == color:
                 return False
            #未着色の頂点があったら反転した色と共にスタックに積む
            if colors[to] == 0:
                 stack.append((to, -color))
    #調べ終わったら矛盾がないのでTrue
    return True

print(is_bipartite())

DFSを初めて覚えたとき、再帰なしのコードで覚えたので、こっちのほうが個人的に馴染みがある。
再帰は深さとか気にしなきゃいけないし、動きをイメージしづらいし、デバッグしづらい、って意識があって、あんまり書きたくないと思ってた。
でもこうやって比較すると、なるほどこのDFSだと再帰のほうがコードがすっきりしてる。
(イメージのしづらさとかは置いといて)
引き出しは多いほうがいいから、両方書けるようになっておこうっと。

実践例

さて、これでようやく、先日のコドフェ予選BのC問題が解けるようになりました。
問題はこちらです。
C: 3 Steps - CODE FESTIVAL 2017 qual B | AtCoder

(意訳)
N <= 106 頂点を、M <= 106 の辺で結んでいる。
連結な無向グラフで、自己辺や多重ループはない。
3つの辺を経由してたどり着ける(=あいだに2頂点を経由する)2点を全て結ぶように辺を追加するとき、最大で何本の辺を追加できるか。


これ、解く方針がわかりませんでした。
N,M <= 106 のサイズがネックで、私の思いつく解法だとどうしても間に合わない。
(全ての頂点から伸びてる辺、のそのまた先の伸びてる辺、を調べるだけで、 O(NM) ぐらい?にはなってしまう気がした。)
小手先の工夫でゴリゴリやって倒せる相手じゃなかった。

解説を見たら、魔法みたいな解法がありました!
どうも、探索で解くというよりは、グラフの性質を使って解く模様。
より詳しくは、解説を見てね。(私レベルには若干わかりづらい)

まず、距離が3辺離れた点を繫ぐということは、距離3が1になり、
同様に距離が奇数離れた点の間は2ずつ縮めることができて、そのうち辺を繋げる!
なるほどなぁ。。気づかなかった。。

そして、ここで、2部グラフが登場する。
2部グラフの場合、自分チームと相手チームを結んでいる辺しか存在しない。
どの頂点からも、奇数個の辺をたどって行ける頂点は相手チームで、偶数個の辺をたどって行ける頂点は自分チーム。
もちろん1辺の両端は異なるチームだし、3辺離れた頂点同士も、異なるチームになる。
とすると、この問題のルールにおいては、同じチーム同士はどうやっても結べない!

反対に、2部グラフでなければ、どこかしらの2点間は
奇数個の辺をたどっていくルートと、偶数個の辺をたどっていくルートが存在する
ということだから、全ての辺は、いずれ繋ぐことができる!

なので、結論は

  • 2部グラフなら、黒・白と塗った頂点数をB,Wとして、B*W - M本。
  • 2部グラフでなければ、全頂点間が結ばれるので、 N(N-1)//2 - M本。

になるらしい。
すっごーい !!

早速、上で書いたコードをぺたりと貼り付けて、ACもらってきました!

import sys
sys.setrecursionlimit(10**7)
 
N,M = map(int,raw_input().split())
es = [[] for i in range(N)]
for i in range(M):
    a,b = map(int,raw_input().split())
    a,b = a-1,b-1
        es[a].append(b)
        es[b].append(a)
 
colors = [0 for i in range(N)]
 
def dfs(v,color):
    colors[v] = color
    for to in es[v]:
        if colors[to] == color:
            return False
        if colors[to] == 0 and not dfs(to, -color):
            return False
    return True
 
def is_bipartite():
    return dfs(0,1)
 
if is_bipartite():
    b = (sum(colors) + N) // 2
    w = N-b
    print(b*w - M)
else:
    all = N*(N-1) // 2
    print(all - M)

なお、2部グラフ判定のところ、再帰版ではAC取れたけど、
再帰なし版もsubmitしたら、テストケースが1つTLEだった。
ステップ数はさほど変わらないような気がするが、、ナゼだ。。
どなたか分かる方、ご教授ください。。。(考察放棄)

この問題のキモ

この問題、見抜かなきゃいけないことがたくさんありました。

  • N,M <= 106 のサイズは、工夫したところで、隣の隣の、、みたいな探索は到底できないこと。
  • グラフの性質を使って計算で解く問題ということ。
  • 奇数個離れた頂点なら、いずれ、全て結ぶことができること。
  • 2部グラフかどうかで答えの方針が変わること。

2部グラフを知っていなきゃ解けない問題だったのだけど、
知らなかったとしても、3番目のポイントまで見抜いていなければ、どのみち解けなかったという。

ぐぬぬ
精進します!

CODE FESTIVAL 2017 qual B

結果

A,Bの2完。タイム06:25。549位。
パフォーマンス1598、レート1259→1303(+44)

C,D問題、むずかった。。
そして全然できなかったのにレート上がっちゃった。
少し腑に落ちないと思ったけど、結局どちらも自力でできる内容じゃなかったので、ある意味実力通りか。
どうやったら、あの問題から、2部グラフなんて思いつくようになるんだろう。。。
というか、2部グラフってものは蟻本でさらっと出てきただけで存在を忘れてたし、使ったこともなかった。
次は絶対に解けるようにしとこう。

A XXFESTIVAL

A: XXFESTIVAL - CODE FESTIVAL 2017 qual B | AtCoder

末尾の8文字を除いてprint。

S = input()
print(S[:-8])

B Problem Set

B: Problem Set - CODE FESTIVAL 2017 qual B | AtCoder

N問の問題セットがあって、その中にM問の指定された難易度の問題が含まれているか。
以下、私の回答

import sys
from collections import Counter
 
N = int(input())
s1 = list(map(int,input().split()))
M = int(input())
s2 = list(map(int,input().split()))
 
c1 = Counter(s1)
c2 = Counter(s2)
 
for k,v in c2.items():
    if k in c1:
        if v > c1[k]:
            print('NO')
            sys.exit()
    else:
        print('NO')
        sys.exit()
print('YES')

pythonCounterモジュールを使った。(個人的によく使う)
l = [10,20,30,20] みたいなリストを、Counter(l)とかやると、
{10:1, 20:2, 30:1} みたいなdict型に集計してくれるすごいやつ。
key:valueのうち、keyの方がもともとの要素で、valueの方が集計した個数。(たまに、どっちか混乱する。)

c2.items() でM問の必要な方をループして、N問の用意してある問題セットに1つもないか、問題セットが足りなければNOを出力。
ループが最後まで行けばYESを出力。
こんな感じでしたー。

DISCO presents ディスカバリーチャンネル コードコンテスト 2017 予選

概要

2019卒枠が100人と、その他の100人が本戦に進めるコンテスト。
本戦の告知(DDCC | ディスカバリーチャンネル)を見たら、イベントがすごく豪華。
特に対談のメンバーがすごい。皆憧れの人ばかり。
(将棋界と将棋プログラムのトピックは、ここ何年か、個人的に追いかけているので)
厳しいだろうけど、何としても本戦出たい!って思いで参加しました。

結果

A,B,C の3完。タイム10:20。222位。
C問題までは自分的にベストなパフォーマンスだった。
D問題は1submitしたけど、考察力が足りずWA+TLE。
その他枠の人、100人ぐらい辞退してくれないかな〜??。。
まあ、そんな訳ないので、来年までに力をつけてリベンジするか。。

A,B問題

特に難しいポイントがないので省略。
ダースの12倍がグロス、その12倍がグレートグロスという単位があるのを初めて知った。

以下、 私の回答
A - DDCC型文字列
http://ddcc2017-qual.contest.atcoder.jp/submissions/1656175

B 鉛筆
http://ddcc2017-qual.contest.atcoder.jp/submissions/1656644

C 収納

C: 収納 - DISCO presents ディスカバリーチャンネル コードコンテスト2017 予選 | AtCoder

N <= 100000 本の棒があって、長さCのケースに収納していくとき、ケースの最小数を求める。
ケースには1本か2本入れられて、2本入れる場合は[2本の和 + 1]の長さが必要。

以下、私の回答

N,C = map(int,input().split())
src = [int(input()) for i in range(N)]
src.sort()
 
l = 0
r = N-1
ans = 0
while l <= r:
    if src[l] + src[r] + 1 <= C:
        l += 1
    ans += 1
    r -= 1
print(ans)

ソートして左右から貪欲でいけた。
一番長いのを一番短いのと一緒に詰めることができれば、2本しまう。
そうでなければ、一番長いのを1本しまう。

例として、入力例1の C=10, L=[2,8,4,5]の場合。

  • ソートする。L=[2,4,5,8]
  • 2+8+1 > 10 で、8は単独で入れるしかないので、8をしまう。ans=1, L=[2,4,5]
  • 2+5+1 <= 10で、2と5が両方入るので、両方しまう。ans=2, L=[4]
  • 最後に4をしまう。ans=3

こんな感じ。

実際は、lとrの2つのインデックスを操作すれば、配列の要素を消すことなく、シミュレーションできる!
計算量は、

  • ソートにO(NlogN)
  • 貪欲なシミュレーションがO(N)

O(NlogN) なので大丈夫!

最後にちょっと脱線

このブログについて、本当は勉強したことをまとめていって自分用のノートにするつもりだったけど、気づいたら競プロの参加記になってた件。

まとめたいネタはいくつかあるんだけど、どうも、人が見て分かるような体裁にまとめるのが苦手というか、意外と骨が折れることが分かった。
記事にまとめるのより、過去問にチャレンジした方が楽しい ^^;。

まあ、無理せず、自分のペースでやればいっか。

Kyoto University Programming Contest 2017

結果

A,B の2完。タイム08:06。165位。
初の5時間越えのコンテストに参加するので、お菓子に飲み物と万全の体制で臨んだ。
なのに、C問題以降が難しすぎて、早々にダレてしまった。
これだけ時間があったら、せめてC問題は解きたかった...。
おのれ、京都大学ぅ〜。
後で解説きたら勉強させてもらおう...。


A Credits

A: Credits - Kyoto University Programming Contest 2017 | AtCoder

できるだけ少ない科目数で必要単位を取る場合の科目数を答える問題。

需要あるか分からないけど、コードペタペタしていく。

N,K = map(int,input().split())
src = list(map(int,input().split()))
src.sort(reverse=True)
ans = c = 0
for i in range(N):
    c += src[i]
    ans += 1
    if c >= K:
        print(ans)
        break
else:
    print(-1)

降順にソートして、貪欲に単位数を足していって、必要単位Kに達したらbreak。
全部足してもKに達しなかったら、-1。
Nは50までなので、計算量も余裕。


B Camphor Tree

B: Camphor Tree - Kyoto University Programming Contest 2017 | AtCoder

完全二分木の形のくすのきがあって、ある分岐Sからある分岐Tに登れるか。 登れる場合は距離を出力。登れない場合は-1。

N,S,T = map(int,input().split())
 
n = T
ans = 0
while(n >= S):
    if n == S:
        print(ans)
        break
    ans += 1
    n //= 2
else:
    print(-1)

完全二分木の性質を知っていれば楽勝でした。
2で割れば、1つ親のノードに行けるので、Sを2で割っていってTにたどり着けるかどうか。
木の高さN=25なので、計算量も余裕。

天下一プログラマーコンテスト2017

結果

C,Dの2完。タイム85:20、264位。
レート上がる気がしたけど、Unratedの模様。
まあ、楽しかったので気にしない。

C: 4/N

C: 4/N - Tenka1 Programmer Contest | AtCoder

4⁄N = 1⁄h + 1⁄n + 1⁄w
式を満たす正整数h, n, w を求めよ、って問題。 (h, n, wって何の意味だろう...)


h,n,w <= 3500 を満たす解が存在するとのことだけど、
組み合わせを全部試すのはO(M3)でもちろん無理。M=3500。

よく考えたら3つの変数のうち2つが決まれば、残り1つが計算で求まるので、
ループするのは2つでおk。
求めた結果が正の整数だったらそれが答え。

M2 だと107 ループ位だから、イケる、、
いや、Pythonだと非常に際どいなー。どうかなー。
と思いながらも、下のようなコードを書いた。

import sys
N = int(input())

def is_int(a):
    return (abs(a - int(a)) < 0.1**8)

for a in range(1, 3501):
    for b in range(a, 3501):
        tmp = 4/N - 1/a - 1/b
        if tmp <= 0: continue
        if is_int(1/tmp):
            c = int(1/tmp)
            print(a, b, c)
            sys.exit()

is_int() は整数判定のために書いたコード。
浮動小数==で比較するのって誤差ありそうでマズかった気がした。
許容誤差10-8 ってのも適切なのか全然分からないけど、もう、エイッと8(エイト)を書いた。

それで、サンプルケース動かしてみたら、
やっぱり、明らかに3つ目のケースで3秒以上かかったのでダメ。
内側のbのループを、1じゃなくaから始めて、ループを半分にする工夫をしてもダメ。

これ以上考えてもしょうがないと思い、上のコードはsubmitせず、Javaで書き直し。
メインPythonなので、TLE対策で最近この手口を使っている。
(最初からそっちで書けよ、と言われそうだけど、いろいろメンドくさいのよ。。。)

というわけで無事にAC。やったね!

Submission #1638385 - Tenka1 Programmer Contest | AtCoder

D: IntegerotS

D: IntegerotS - Tenka1 Programmer Contest | AtCoder

整数A と その価値B の組み合わせが N個与えられて、
そこからいくつか選んで、価値の総和を最大化する問題。
ただし、選んだ整数を全てbitwise OR したときに、Kを超えちゃいけない。


下のコードでACできた!

N,K = map(int,input().split())
masks = [K]

bs = str(bin(K))[2:]
for i in range(len(bs) - 1):
    if bs[i] == '1':
        a = len(bs) - 1 - i
        mask = K - (1 << a)
        mask |= ((1 << a) - 1)
        masks.append(mask)

anss = [0 for i in range(len(masks))]
for i in range(N):
    a,b = map(int,input().split())
    for i,m in enumerate(masks):
        if (m | a) == m:
            anss[i] += b

print(max(anss))

Kが 1010010(2) だとしたら、調べるべき、使えるビット(mask) のパターンは

  • 1010010 (K自身)
  • 0111111 (Kの1番目の1を0にして、あと全部1)
  • 1001111 (Kの2番目の1を0にして、あと全部1)
  • 1010001 (Kの3番目の1を0にして、あと全部1)

の4通りで十分。
なぜなら、例えば0111111(2) の他に、0111110(2)もK以下の数だけど、
最下位のビットを使っていいのと、いけないのでは、使っていい方が価値の総和が高いに決まってる。(価値は正の値)

ちなみに、こういうビットのパターンのこと、マスクって呼び方であってるのか、ちょっと不安。
まあ誰も気にしないか。

ビットを扱うのは慣れてないので、いつも考察に時間がかかっちゃうのが課題。
最初、上の例でいう0111111 しか見えてなかったので、
その方針で解けなかったときはちょっと絶望した。
でも、なんとか時間内に解けたのは、僥倖!

Submission #1640474 - Tenka1 Programmer Contest | AtCoder

競プロと出会うまで(前編)

ブログを始めました。

prd_xxx です。

 

人生初のブログなので分からないことだらけですが、

少しずつ覚えていきたいです。

よろしくお願いします。

 

競プロ(競技プログラミング) を4ヶ月前に始めました。

そこに至るまでの話をします。

 

プログラミング自体は、15年くらい前、

高校の時に選択授業で習ったのが最初でした。

 

高2のころ、選択授業でプログラミングをとりました。

C言語で、九九の表か何かを作って喜んでいました。

わーい! たのしーと思いました。

 

高3でも選択授業でプログラミングをとりました。

Javaで、Swingか何かで 、グラフィカルでインタラクティブな何かをやりました。

正直、ダメかも、、と思いました。

 

教材のソースコードが長すぎるうえ、

何をどうすればどうなるか、を

全然理解しないまま授業は終わりました。

 

年度の終わりに、自由な作品を作る機会があったのですが、

超できる人が凝った作りのビリヤードゲームを作ってたのが印象的でした。

私はというと、やはり九九の表に毛が生えたレベルの何かでした(笑)

この時点でセンスのなさを悟りました。

未だにあのクオリティのは作れる気がしません

 

そうは言っても、大学では特にやりたいこともなく、

消去法のような決め方でCS学科(情報科学)に進みました。  

そこでは当然、苦難の連続で、挫折 and 挫折の繰り返しでした。

 

まず当時はオブジェクト指向が理解できませんでした(笑)

カプセル化?継承? なにそれおいしいの的な。

 

結果として、必修科目のプログラミングをN年連続で落とし、卒業にN+3年かかりました。

もう、CS学科の最底辺だったかもしれません。

他の科目も壊滅的にダメでした。

でも変なプライドだけは一人前で、大学では孤高のぼっちを極めてました。

 

それでも、中退か?卒業を目指すか?を真剣に考えたときは、

やっぱり大卒の資格を諦めきれませんでした。

その頃から、本気を出して、頑張りだしたようにおもいます。

ただし、そこからは単位を稼ぐことを最優先にしたため、

ほとんどが付け焼刃の、試験翌日には忘れてるタイプの勉強になってしまいました。

 

というわけで私の最終学歴は学部卒ですが、

1つ後悔してることがあります。

それは、学ぶのに最適な環境、最適な立場であったにもかかわらず、

学業に対して真摯に取り組めなかったことです。

 

......今ではその後悔を払拭するかのように、競プロにのめり込んでいます!

という話をしたいのですが、 

思ったより長くなってしまったので後編に続きます。