kmjp's blog

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

yukicoder : No.2677 Minmax Independent Set

これは割とすんなり。
https://yukicoder.me/problems/no/2677

問題

木を成す無向グラフが与えられる。
初期状態で全点は白く塗られている。
先手が1点黒く塗った後、後手は好きなだけ点を黒く塗れる。
ただし黒点が隣接してはならない。

先手は黒点数を最小化、後手は最大化するとき、黒点数はどうなるか。

解法

各点を黒くした場合、それぞれ黒点数を最大化するように他の点を塗ることを考える。
先手は、そのうち黒点数が最小となる点を最初に選べばよい。

あとは、各点を黒くした場合に黒点数を最大化するとどうなるかを求めればよい。
これは典型的な全方位木DPで、SubTreeの根を黒く塗った場合と塗らない場合の黒点数の最大値を求めればよい。

int N;
vector<int> E[202020];
int dp[202020][2];
int ret;

void dfs(int cur,int pre) {
	dp[cur][1]=1;
	FORR(e,E[cur]) if(e!=pre) {
		dfs(e,cur);
		dp[cur][1]+=dp[e][0];
		dp[cur][0]+=max(dp[e][0],dp[e][1]);
	}
}

void dfs2(int cur,int pre,int dp0,int dp1) {
	dp[cur][1]+=dp0;
	dp[cur][0]+=max(dp1,dp0);
	
	ret=min(ret,dp[cur][1]);
	
	FORR(e,E[cur]) if(e!=pre) {
		dfs2(e,cur,dp[cur][0]-max(dp[e][0],dp[e][1]),dp[cur][1]-dp[e][0]);
	}
}

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N;
	FOR(i,N-1) {
		cin>>x>>y;
		E[x-1].push_back(y-1);
		E[y-1].push_back(x-1);
	}
	ret=N;
	dfs(0,0);
	dfs2(0,0,0,0);
	cout<<ret<<endl;
}

まとめ

これは★3でもいいかもね。