1. 程式人生 > >Codeforces 1105E 最大獨立集 狀態DP 中途相遇法

Codeforces 1105E 最大獨立集 狀態DP 中途相遇法

其中 bits int 題意 lag can 不同的 處理 ring

題意:你有一個字符串, 有兩種操作,一種是改變字符串,一種是某個用戶詢問這個字符串,如果一個用戶每次查詢字符串的時候都是他的用戶名,他就會高興。問最多有多少個用戶會高興?

題意:容易發現,在兩個1操作之間,如果有多個用戶的的詢問,只能滿足一個。換句話說,如果滿足了其中的一個,那麽其它的便不能滿足。我們可以對所有兩個1之間的操作兩兩連邊,那麽問題就變成了最大獨立集問題。

對於這個問題,可以用狀壓DP解決,但是最多有40個不同的用戶,所以需要分成兩半,分別預處理,然後枚舉其中的一半,在保證於這邊一半不相交的情況下,找到對應的另一半。

代碼:

#include <bits/stdc++.h>
using namespace std;
int f[1 << 20], g[1 << 20];
map<string, int> mp;
int G[50][50];
vector<int> v;
int cnt;
string s;
int main() {
	int n, m, op;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &op);
		if (op == 1) {
			v.clear();
			continue;
		} else {
			cin >> s;
			if(!mp.count(s))
				mp[s] = cnt++;
			v.push_back(mp[s]);
			for (int j = 0; j < v.size() - 1; j++)
				G[v[j]][v[v.size() - 1]] = G[v[v.size() - 1]][v[j]] = 1;
		}
	}
	if(v.size()) {
		for (int j = 0; j < v.size() - 1; j++)
			G[v[j]][v[v.size() - 1]] = G[v[v.size() - 1]][v[j]] = 1;
	}	
	int s1 = m / 2;
	int s2 = m - s1;
	for (int i = 0; i < (1 << s1); i++) {
		for (int j = 0; j < s1; j++) {
			if(((i >> j) & 1) == 0) {
				int flag = 1;
				for (int k = 0; k < s1; k++) {
					if((i >> k) & 1)
						if(G[j][k] == 1) {
							flag = 0;
							break;
						} 
				}
				f[i | (1 << j)] = max(f[i | (1 << j)], f[i] + flag);
			}
		}
	}
	for (int i = 0; i < (1 << s2); i++) {
		for (int j = 0; j < s2; j++) {
			if(((i >> j) & 1) == 0) {
				int flag = 1;
				for (int k = 0; k < s2; k++) {
					if((i >> k) & 1)
						if(G[j + s1][k + s1] == 1) {
							flag = 0;
							break;
						} 
				}
				g[i | (1 << j)] = max(g[i | (1 << j)], g[i] + flag);
			}
		}
	}
	int ans = 0;
	for (int i = 0; i < (1 << s1); i++) {
		int now = (1 << s2) - 1;
		for (int j = 0; j < s2; j++) {
			for (int k = 0; k < s1; k++) {
				if((i >> k) & 1)
					if(G[k][j + s1] == 1) {
						now ^= (1 << j);
						break;
					} 
			}
		}
		ans = max(ans, f[i] + g[now]);
	}
	printf("%d\n", ans);
} 

  

Codeforces 1105E 最大獨立集 狀態DP 中途相遇法