kmjp's blog

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

yukicoder : No.1690 Power Grid

これは★3にしては簡単。
https://yukicoder.me/problems/no/1690

問題

N個の町と、町同士をつなぐM個の道路がある。
各道路には長さが設定されている。

ここで、K個の町に発電所を作りたい。
その際のコストは以下の通りである。

  • i番の町に発電所を作ると、A[i]の追加コストがかかる。
  • 2個目以降の発電所を作る際は、既存の発電所があるいずれかの町までの最短距離分のコストがかかる。

K個の町に発電所を作る場合の総コストを求めよ。

解法

まずWarshall-Floyd法で、任意の町の間の最短距離を求めておこう。
dp(mask) := maskに対応する町に発電所を作る総コストの最小値
とすると、現状の次にどこの町に発電所を追加するかを考えると、このBitDPはO(N^2*2^N)で解ける。

int N,M,K;
ll dp[18][18];
int A[18];
ll dp2[1<<18];

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N>>M>>K;
	FOR(i,N) cin>>A[i];
	
	FOR(x,N) FOR(y,N) dp[x][y]=(x==y)?0:(1LL<<60);
	FOR(i,M) {
		cin>>x>>y>>k;
		dp[x-1][y-1]=dp[y-1][x-1]=k;
	}
	FOR(k,N) FOR(x,N) FOR(y,N) dp[x][y]=min(dp[x][y],dp[x][k]+dp[k][y]);
	
	FOR(i,1<<N) dp2[i]=1LL<<60;
	FOR(i,N) dp2[1<<i]=A[i];
	int mask;
	ll ret=1LL<<60;
	FOR(mask,1<<N) if(mask) {
		FOR(x,N) if((mask&(1<<x))==0) {
			ll mi=1LL<<60;
			FOR(y,N) if(mask&(1<<y)) mi=min(mi,dp[x][y]);
			dp2[mask|(1<<x)]=min(dp2[mask|(1<<x)],dp2[mask]+A[x]+mi);
		}
		if(__builtin_popcount(mask)==K) ret=min(ret,dp2[mask]);
	}
	
	cout<<ret<<endl;
	
}

まとめ

特に妙なヒネリもなく素直な問題。