CodeForces 1250E [2-sat]

題目鏈接:https://codeforces.com/contest/1250/problem/E

 

解題思路:

首先根據反轉的性質有:

       有字符串a,b,a的反轉A,b的反轉B,如果a和b匹配值爲K,那麼A和B的值也爲K

        同樣a和B匹配值爲M,那麼A和b的匹配值也爲M,因此有對稱性

那麼就可以轉換成2-sat問題了,設點i的對立點集是i+n,也就是a和A

       如果i和j不管怎麼反轉都能匹配,那麼他們之間就沒有約束關係

       如果i和j不管怎麼反轉都不匹配,那麼直接是無解的

       如果i只能和j匹配,不能和j+n匹配,那麼聯合i和j,聯合i+n,j+n

       如果只能和j+n匹配,那麼聯合i和j+n,聯合i+n,j

這個就可以用並查集維護,然後因爲我們需要更少的反轉,所以加上加權並查集,選擇權值較小的i集合或者i+n集合

#include<bits/stdc++.h>
using namespace std;
const int mx = 100+5;
const int mod = 1e9 + 7; 
typedef long long ll;
int n,m,K;
int fa[mx],siz[mx],ans[mx];
char s[mx][mx];
vector <int> g[mx];
int find(int x) {
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
bool check(int u,int v) {
	int cnt = 0;
	for (int i=0;i<m;i++)
		cnt += s[u][i] == s[v][i];
	return cnt >= K;
}
bool solve() {
	for (int i=0;i<n;i++) {
		for (int j=i+1;j<n;j++) {
			bool ok1 = check(i,j);
			bool ok2 = check(i,j+n);
			if (!ok1 && !ok2) return 0;
			if (ok1 && ok2) continue;
			int fi = find(i),fj = find(j);
			int fi_n = find(i+n),fj_n = find(j+n);
			if (ok2) swap(fj,fj_n);
			if (fi == fj_n) return 0;
			if (fi != fj) {
				fa[fj] = fi;
				siz[fi] += siz[fj];
				fa[fj_n] = fi_n;
				siz[fi_n] += siz[fj_n]; 
			}
		}
	}
	return 1;
}
int main(){
	int t;
	scanf("%d",&t);
	while (t--) {
		scanf("%d%d%d",&n,&m,&K);
		for (int i=0;i<2*n;i++) {
			fa[i] = i;
			siz[i] = i >= n;
			g[i].clear();
		}
		for (int i=0;i<n;i++) {
			scanf("%s",s[i]);
			reverse(s[i],s[i]+m);
			memcpy(s[i+n],s[i],m+1);
			reverse(s[i],s[i]+m);
		}
		bool ok = solve();
		if (!ok) puts("-1");
		else {
			vector <int> ve;
			int tot = 0;
			for (int i=0;i<2*n;i++) {
				int fi = find(i);
				g[fi].push_back(i);
			}
			for (int i=0;i<n;i++) {
				int fi = find(i);
				int fi_n = find(i+n);
				if (fi != i) continue;
				if (siz[fi] <= siz[fi_n]) ve.push_back(fi);
				else ve.push_back(fi_n);
			}
			for (int u : ve) {
				for (int v :g[u])
					if (v >= n) ans[tot++] = v - n + 1;
			}
			if (!tot) puts("0\n");
			else {
				printf("%d\n",tot);
				for (int i=0;i<tot;i++)	
					printf("%d%c",ans[i],i==tot-1?'\n':' ');
			} 
		}
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章