kmjp's blog

競技プログラミング参加記です

TopCoder SRM 788 : Div1 Easy RailwayMaster

久々にレート増。
https://community.topcoder.com/stat?c=problem_statement&pm=16138&rd=18085

問題

連結無向グラフが与えられる。
各辺には価値が設定されている。
このグラフが連結である状態を保ったまま、最大K本まで辺を取り除くことができる。
取り除く辺の価値の和の最大値を求めよ。

解法

まず最小全域木を求めよう。
そうするとそれ以外の辺は残しても取り除いてもよいので、価値の大きい順にK本まで取り除く。

template<int um> class UF {
	public:
	vector<int> par,rank,cnt;
	UF() {par=rank=vector<int>(um,0); cnt=vector<int>(um,1); for(int i=0;i<um;i++) par[i]=i;}
	void reinit() {int i; FOR(i,um) rank[i]=0,cnt[i]=1,par[i]=i;}
	int operator[](int x) {return (par[x]==x)?(x):(par[x] = operator[](par[x]));}
	int count(int x) { return cnt[operator[](x)];}
	int operator()(int x,int y) {
		if((x=operator[](x))==(y=operator[](y))) return x;
		cnt[y]=cnt[x]=cnt[x]+cnt[y];
		if(rank[x]>rank[y]) return par[x]=y;
		rank[x]+=rank[x]==rank[y]; return par[y]=x;
	}
};


class RailwayMaster {
	public:
	int maxProfit(int N, int M, int K, vector <int> a, vector <int> b, vector <int> v) {
		UF<101> uf;
		
		vector<pair<int,int>> E;
		int i;
		FOR(i,M) E.push_back({v[i],i});
		sort(ALL(E));
		
		vector<int> cand;
		FORR(e,E) {
			int x=a[e.second];
			int y=b[e.second];
			if(uf[x]==uf[y]) {
				cand.push_back(e.first);
			}
			else {
				uf(x,y);
			}
		}
		
		reverse(ALL(cand));
		if(cand.size()>K) cand.resize(K);
		ll ret=0;
		FORR(c,cand) ret+=c;
		return ret;
	}
}

まとめ

またえらい典型問題っぽいのが出てきたな。