AOJ 2011 Gather the Maps!

問題
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2011

解法
T日にスケジュールのあいている子孫の集合をCtとする
子孫cがT日に持っている地図の集合をMctとする

Mct = Mc(t-1) (c ∈ Ct でない)
   ∪{Md(t-1) | d ∈ Ct} (c ∈ Ct)
を計算していって、
始めてMctが地図全体の集合と等しくなるtを求めればよい

#include <cstdio>
#include <algorithm>
using namespace std;
 
const int MAX_N = 50;
const int DAY = 31;
 
//a[i][j][d] 子孫iはt日の時点でjの持っていた地図を持つことが可能か
bool dp[MAX_N][MAX_N][DAY+1];
//子孫のスケジュール
bool a[MAX_N][DAY];
int main(){
	int N;
	while(scanf("%d", &N) && N!=0 ){
		for(int i=0;i<N;i++)for(int t=0;t<=DAY;t++)
			a[i][t] = false;
		for(int i=0;i<N;i++)for(int j=0;j<N;j++)for(int t=0;t<=DAY;t++){
			dp[i][j][t] = (i==j);
		}
		for(int i=0;i<N;i++){
			int f;
			scanf("%d", &f);
			for(int j=0; j<f; j++){
				int d;
				scanf("%d", &d);
				a[i][d] = true;
			}
		}
		bool f;
		int t;
		for(t=1;t<=DAY;t++){
			bool chi[N]; //t日にスケジュールのあいている子孫
			bool m[N];   //地図
			f = true;
			fill(chi, chi + N, false);
			fill(m, m + N, false);
			for(int i=0; i<N; i++){
				chi[i] = a[i][t];
				if(chi[i]){
					for(int j=0; j<N; j++){
						m[j] = m[j] || dp[i][j][t-1];
					}
				}
			}
			for(int j=0;j<N;j++){
				f=f&&m[j];
			}
			if(f) break;
			for(int i=0; i<N; i++){
				if(!chi[i]){
					for(int j=0; j<N; j++)
						dp[i][j][t] = dp[i][j][t-1];
				}else{
					for(int j=0; j<N; j++)
						dp[i][j][t] = m[j];
				}
			}
		}
 		if(f && t <= 30){
			printf("%d\n", t);
		}else printf("-1\n");
	}
	return 0;
}