TopCoder SRM 312 Div1 Medium AntarcticaPolice
問題
n個の都市が、一方通行の道でつながっている。
それぞれの都市に警察を置くコストがcosts[i]により与えられる。
全ての都市に、「その都市または、その都市へ行くことが出来る都市のどれかひとつ」に警察が置かれている状態にしたい。
この状態で、警察を置くコストの、警察署一つあたりのコストの最小値を求めよ。
制約条件
n≦50
costs[i]≦1000
方針
強連結成分分解を行う。
SCC後のグラフはDAGになっていて、DAGの根に当たるノードには必ず警察署を作らなければならない。
根に当たるノードが複数の頂点からできていたら、その中で最も安いコストの都市に警察署を作ればよい。
その後、使ってないノードを適当に追加して平均を小さくできるか見る。
これは、使ってないノードをコストの小さい順にソートして、平均が下がる間そのノードを貪欲に使うことにすればいい。
ソースコード
強連結成分分解は蟻本実装。
const int MAX_V=100; int V; vi G[MAX_V], rG[MAX_V], vs; bool used[MAX_V]; int cmp[MAX_V]; void add_edge(int from,int to){ G[from].pb(to); rG[to].pb(from); } void dfs(int v){ used[v]=1; rep(i,G[v].size())if(!used[G[v][i]])dfs(G[v][i]); vs.pb(v); } void rdfs(int v,int k){ used[v]=1; cmp[v]=k; rep(i,rG[v].size())if(!used[rG[v][i]])rdfs(rG[v][i],k); } int scc(){ memset(used,0,sizeof(used)); vs.clear(); rep(v,V)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; } class AntarcticaPolice { public: double minAverageCost(vector <int> costs, vector <string> roads) { V=costs.size(); rep(i,V)G[i].clear(), rG[i].clear(); rep(i,V)rep(j,V)if(roads[i][j]=='Y')add_edge(i,j); int k=scc(), deg[50]={}; bool e[50][50]={}; rep(i,V)rep(j,V)if(roads[i][j]=='Y')e[cmp[i]][cmp[j]]=1; rep(i,k)rep(j,k)if(i!=j&&e[i][j])deg[j]++; bool use[50]={}; int sum=0, m=0; rep(i,k)if(deg[i]==0){ int mni=-1; rep(j,V)if(cmp[j]==i){ if(mni<0||costs[j]<costs[mni])mni=j; } use[mni]=1; sum+=costs[mni]; m++; } vi v; rep(i,V)if(!use[i])v.pb(costs[i]); sort(all(v)); double ans=sum*1.0/m; rep(i,v.size()){ if((sum+v[i])/(m+1.0)<ans){ ans=(sum+v[i])/(m+1.0); sum+=v[i]; m++; } } return ans; } };