TopCoder SRM 357 Div1 Medium WebsiteRank

問題

いくつかのwebサイトのリンクの関係が与えられる。
websiterankとは次のような値である。


最初、全てのサイトの値は1.
サイトAからサイトBへリンクがあるとき、サイトBの値にサイトAの値を足す。
ただし、サイトBからサイトAへ直接、または間接的にリンクがあるときは足さない。


このようにして得られる値のうち、websiteの名前のサイトの値を求めよ。

制約条件

リンクは文字列のリストの形式で与えられる。
webサイトの総数は1200くらい。

方針

ループしている部分では値を足してはいけないので、
強連結成分分解して、同じ強連結成分内のエッジは全て消すようにする。


するとDAGになるので、後は普通にDPして値を求めればいい。


入力のサイズは50だが、サイトの総数は1200くらいになりうるので注意する。

ソースコード

int n;
vector<set<int> > e, re;
bool used[2000];
int cmp[2000];
ll ans[2000];
vi vs;

void add_edge(int a, int b){
	e[a].insert(b);
	re[b].insert(a);
}
void dfs(int v){
	used[v] = 1;
	each(i, e[v]) if(!used[*i]) dfs(*i);
	vs.pb(v);
}
void rdfs(int v, int k){
	used[v] = 1;
	cmp[v] = k;
	each(i, re[v]) if(!used[*i]) rdfs(*i, k);
}
int scc(){
	memset(used, 0, sizeof(used));
	vs.clear();
	rep(v, n) if(!used[v]) dfs(v);
	memset(used, 0, sizeof(used));
	int k = 0;
	for(int i = vs.size() - 1; i >= 0; i--)
		if(!used[vs[i]]) rdfs(vs[i], k++);
	return k;
}

ll rec(int c){
	ll &res = ans[c];
	if(res >= 0) return res;
	
	res = 1;
	each(i, re[c]) res += rec(*i);
	return res;
}

class WebsiteRank {
	public:
	long long countVotes(vector <string> votes, string website) 
	{
		n = 0;
		map<string, int> id;
		
		rep(i, votes.size()){
			stringstream ss(votes[i]);
			string s;
			while(ss >> s){
				if(!id.count(s)) id[s] = n++;
			}
		}
		
		e.clear(); re.clear();
		e.resize(n); re.resize(n);
		
		rep(i, votes.size()){
			stringstream ss(votes[i]);
			string s, t;
			ss >> t;
			while(ss >> s) add_edge(id[s], id[t]);
		}
		
		int nc = scc();
		
		rep(i, nc){
			vi v;
			rep(j, n) if(cmp[j] == i) v.pb(j);
			rep(j, v.size()) rep(k, v.size())
			re[v[j]].erase(v[k]), re[v[k]].erase(v[j]),
			e[v[j]].erase(v[k]), e[v[k]].erase(v[j]);
		}
		
		rep(i, n) ans[i] = -1;
		rep(i, n) if(e[i].size() == 0) rec(i);
		
		return ans[id[website]];
	}
};