Problem:
Score : 300 points

Problem Statement

There are N people numbered 1 to N. Each of them is either an honest person whose testimonies are always correct or an unkind person whose testimonies may be correct or not.

Person i gives A_i testimonies. The j-th testimony by Person i is represented by two integers x_{ij} and y_{ij}. If y_{ij} = 1, the testimony says Person x_{ij} is honest; if y_{ij} = 0, it says Person x_{ij} is unkind.

How many honest persons can be among those N people at most?

Constraints

All values in input are integers.

1 \leq N \leq 15

0 \leq A_i \leq N - 1

1 \leq x_{ij} \leq N

x_{ij} \neq i

x_{ij_1} \neq x_{ij_2} (j_1 \neq j_2)

y_{ij} = 0, 1

Input

Input is given from Standard Input in the following format:

N
A_1
x_{11} y_{11}
x_{12} y_{12}
:
x_{1A_1} y_{1A_1}
A_2
x_{21} y_{21}
x_{22} y_{22}
:
x_{2A_2} y_{2A_2}
:
A_N
x_{N1} y_{N1}
x_{N2} y_{N2}
:
x_{NA_N} y_{NA_N}

Output

Print the maximum possible number of honest persons among the N people.

Sample Input 1

3
1
2 1
1
1 1
1
2 0

Sample Output 1

2

If Person 1 and Person 2 are honest and Person 3 is unkind, we have two honest persons without inconsistencies, which is the maximum possible number of honest persons.

Sample Input 2

3
2
2 1
3 0
2
3 1
1 0
2
1 1
2 0

Sample Output 2

0

Assuming that one or more of them are honest immediately leads to a contradiction.

Sample Input 3

2
1
2 0
1
1 0

Sample Output 3

1

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;

class Program {
    static void Main(string[] args) {
        int N;
        Input(out N);
        bool?[][] s = new bool?[N][];
        for(int i = 0; i < N; i++) {
            int A;
            Input(out A);
            s[i] = new bool?[N];
            for(int j = 0; j < N; j++) {
                s[i][j] = null;
            }
            for(int j = 0; j < A; j++) {
                int x;
                int y;
                Input(out x, out y);
                s[i][x - 1] = y == 1 ? true : false;
            }
        }
        int max = 0;
        bool[][] flags = GetAllBitFlags(N);
        //2^N通りを全て探索
        for(int i = 0; i < (1 << N); i++) {
            bool isOk = true;
            int count = 0;
            //全ての人を探索
            for(int j = 0; j < N; j++) {
                //i番目の状況でj番目の人が正直者だと仮定されるならば
                if(flags[i][j]) {
                    //j番目の人の証言を全て探索
                    for(int k = 0; k < s[j].Length; k++) {
                        //j番目の人のk番目の人への証言があるならば
                        if(s[j][k] != null) {
                            //その証言が正直者ならば
                            if((bool)s[j][k]) {
                                if(flags[i][k] == false) {
                                    isOk = false;
                                }
                            } else {
                                if(flags[i][k] == true) {
                                    isOk = false;
                                }
                            }
                        }
                    }
                    count++;
                }
            }
            if(!isOk) {
                count = 0;
            }
            if(max < count) {
                max = count;
            }
        }
        Console.WriteLine(max);
    }
    static bool[][] GetAllBitFlags(int N) {
        bool[][] ret = new bool[1 << N][];
        for(int i = 0; i < (1 << N); i++) {
            ret[i] = new bool[N];
            for(int j = 0; j < N; j++) {
                if((1 & (i >> j)) == 1) {
                    ret[i][j] = true;
                }
            }
        }
        return ret;
    }
    static int[] GetSequence(int first, Func<int, int> recurrence, int n) {
        int[] ret = new int[n];
        ret[0] = first;
        for(int i = 1; i < n; i++) {
            ret[i] = recurrence.Invoke(ret[i - 1]);
        }
        return ret;
    }
    static T ChangeT<T>(string s) => (T)Convert.ChangeType(s, typeof(T));
    static void Input<A>(out A a) {
        var words = Console.ReadLine().Split(new[] { ' ' }, options: StringSplitOptions.RemoveEmptyEntries);
        a = ChangeT<A>(words[0]);
    }
    static void Input<A, B>(out A a, out B b) {
        var words = Console.ReadLine().Split(new[] { ' ' }, options: StringSplitOptions.RemoveEmptyEntries);
        a = ChangeT<A>(words[0]);
        b = ChangeT<B>(words[1]);
    }
    static void Input<A, B, C>(out A a, out B b, out C c) {
        var words = Console.ReadLine().Split(new[] { ' ' }, options: StringSplitOptions.RemoveEmptyEntries);
        a = ChangeT<A>(words[0]);
        b = ChangeT<B>(words[1]);
        c = ChangeT<C>(words[2]);
    }
    static void Input<A, B, C, D>(out A a, out B b, out C c, out D d) {
        var words = Console.ReadLine().Split(new[] { ' ' }, options: StringSplitOptions.RemoveEmptyEntries);
        a = ChangeT<A>(words[0]);
        b = ChangeT<B>(words[1]);
        c = ChangeT<C>(words[2]);
        d = ChangeT<D>(words[3]);
    }
    static void Input<A, B, C, D, E>(out A a, out B b, out C c, out D d, out E e) {
        var words = Console.ReadLine().Split(new[] { ' ' }, options: StringSplitOptions.RemoveEmptyEntries);
        a = ChangeT<A>(words[0]);
        b = ChangeT<B>(words[1]);
        c = ChangeT<C>(words[2]);
        d = ChangeT<D>(words[3]);
        e = ChangeT<E>(words[4]);
    }
    static void Input<A, B, C, D, E, F>(out A a, out B b, out C c, out D d, out E e, out F f) {
        var words = Console.ReadLine().Split(new[] { ' ' }, options: StringSplitOptions.RemoveEmptyEntries);
        a = ChangeT<A>(words[0]);
        b = ChangeT<B>(words[1]);
        c = ChangeT<C>(words[2]);
        d = ChangeT<D>(words[3]);
        e = ChangeT<E>(words[4]);
        f = ChangeT<F>(words[5]);
    }
    static void InputArray<T>(out T[] array) {
        array = Console.ReadLine().Split(new[] { ' ' }, options: StringSplitOptions.RemoveEmptyEntries).Select(s => ChangeT<T>(s)).ToArray();
    }
}