kmjp's blog

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

Codeforces #623 Div1 D. Tourism

B,CよりもAC数が多い。
https://codeforces.com/contest/1314/problem/D

問題

N頂点の有向完全グラフがあり、各辺のコストが与えられる。
ここで、頂点1から始まり頂点1に戻る長さK(Kは偶数)の閉路を考える。
その際、奇数長の閉路を通ることがあってはならない。
条件を満たす閉路の最小コストを求めよ。

解法

頂点対U,Vに対し、U→X→Vと間を1点経由する経路を事前に列挙し、長さを降順に求めておく。
これを踏まえ、2頂点毎に通るパスを総当たりしよう。
例えばK=8なら1→*→A→*→B→*→C→*→1と遷移する。
この時、*の部分は1,A,B,C以外であればいいので、事前に求めた2頂点の移動方法のうち上位5個まで見れば奇閉路の生じない経路を選べる。

vector<pair<ll,int>> M[80][80];
int N,K;
ll mat[81][81];
int A[81];
ll ret=1LL<<60;

void dfs(vector<int>& V) {
	if(V.size()==K/2) {
		V.push_back(0);
		ll sum=0;
		int i;
		FOR(i,K/2) {
			FORR(a,M[V[i]][V[i+1]]) {
				if(A[a.second]==0) {
					sum+=a.first;
					break;
				}
			}
		}
		ret=min(ret,sum);
		V.pop_back();
		return;
	}
	
	int i;
	for(i=0;i<N;i++) {
		V.push_back(i);
		A[i]++;
		dfs(V);
		A[i]--;
		V.pop_back();
	}
}

void solve() {
	int i,j,k,l,r,x,y,z; string s;
	
	cin>>N>>K;
	FOR(y,N) FOR(x,N) cin>>mat[y][x];
	
	FOR(x,N) FOR(y,N) {
		FOR(z,N) if(z!=x && z!=y) {
			M[x][y].push_back(make_pair(mat[x][z]+mat[z][y],z));
		}
		FOR(i,10) M[x][y].push_back({1LL<<50,80});
		sort(ALL(M[x][y]));
	}
	vector<int> V;
	V.push_back(0);
	A[0]++;
	dfs(V);
	
	cout<<ret<<endl;
}

まとめ

Cの方が難しいよね…。