SRM531 Div2 Hard(950) KingdomReorganization
最小全域木。すでに存在する辺eを削除するのにコストCが掛かるというのは、辺の重みを-Cと考えて、あらかじめ重みの総和にCを加えておく。Prim法は重みが負でも動く。
#include <string> #include <vector> #include <queue> #include <utility> using namespace std; int cost( char c ) { return c<='Z' ? c-'A' : c-'a'+26; } struct Edge { int f,t,w; // 始点、終点、重み Edge(int f_,int t_,int w_):f(f_),t(t_),w(w_){} bool operator<(const Edge&e)const{return w<e.w;} }; // 最小全域木(Prim法) int minSpanning( vector<vector<int> > E ) { int n = (int)E.size(); int w = 0; vector<bool> V(n); priority_queue<Edge> Q; Q.push( Edge(0,0,0) ); while ( !Q.empty() ) { Edge e = Q.top(); Q.pop(); if ( V[e.t] ) continue; V[e.t] = true; w -= e.w; for ( int i=0; i<n; i++ ) if ( !V[i] ) Q.push( Edge(e.t,i,-E[e.t][i]) ); } return w; } class KingdomReorganization{public: int getCost( vector <string> kingdom, vector <string> build, vector <string> destroy ) { int N = (int)kingdom.size(); vector<vector<int> > E( N, vector<int>(N) ); for ( int i=0; i<N; i++ ) for ( int j=0; j<N; j++ ) if ( kingdom[i][j]=='0' ) E[i][j] = cost(build[i][j]); else E[i][j] = -cost(destroy[i][j]); int t = 0; for ( int i=0; i<N; i++ ) for ( int j=i+1; j<N; j++ ) if ( kingdom[i][j]=='1' ) t += cost(destroy[i][j]); return t + minSpanning(E); }};