首页 > 技术文章 > CodeForces 1105E

shanxieng 2019-01-21 08:34 原文

题目链接

std:meet in the middle

首先把所有的点分成两部分,设\(f_i\)为前半部分在点集\(i\)中选出的最大独立集,\(g\)为在后半部分选。这个可以在\(O(2^{m/2})\)的时间复杂度里得到。

然后考虑把答案合起来。在f中是从i这个集合里面选出最大独立集,那么后半部分选的集合一定不能有与i相连的边,那么就把i集合里的点的所有与后半部分相连的点标记成不能选,然后在后半部分选剩下的就好了,这些都已经预处理出来了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#include<map>
#include<string>
#include<iostream>
#define qmin(x,y) (x=min(x,y))
#define qmax(x,y) (x=max(x,y))
using namespace std;

inline char gc() {
//	static char buf[100000],*p1,*p2;
//	return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
	return getchar();
}

template<class T>
int read(T &ans) {
	ans=0;char ch=gc();T f=1;
	while(!isdigit(ch)) {
		if(ch==EOF) return -1;
		if(ch=='-') f=-1;
		ch=gc();
	}
	while(isdigit(ch))
		ans=ans*10+ch-'0',ch=gc();
	ans*=f;return 1;
}

template<class T1,class T2>
int read(T1 &a,T2 &b) {
	return read(a)!=EOF&&read(b)!=EOF?2:EOF;
}

template<class T1,class T2,class T3>
int read(T1 &a,T2 &b,T3 &c) {
	return read(a,b)!=EOF&&read(c)!=EOF?3:EOF;
}

typedef long long ll;
const int Maxn=41;
const int Maxm=1100000;
const int inf=0x3f3f3f3f;

bool mp[Maxn][Maxn],vis[Maxn];
map<string,int> name;
int f[Maxm],g[Maxm],ans,m,x,st[Maxn],top,cnt;
int n;
string s;

signed main() {
//	freopen("test.in","r",stdin);
	read(n,m);memset(mp,1,sizeof(mp));
	for(int i=1;i<=n;i++) {
		read(x);
		if(x==1) {
			for(int j=1;j<=top;j++)
				for(int k=j+1;k<=top;k++)
					mp[st[j]][st[k]]=mp[st[k]][st[j]]=0;
			top=0;memset(vis,0,sizeof(vis));
		}
		else {
			cin>> s;
			if(!name.count(s)) name[s]=cnt++;
			int x=name[s];
			if(!vis[x]) {
				vis[x]=0;
				st[++top]=x;
			}
		}
	}
	for(int j=1;j<=top;j++)
		for(int k=j+1;k<=top;k++)
			mp[st[j]][st[k]]=mp[st[k]][st[j]]=0;
	int s1=m/2,s2=m-s1;
	for(int i=0;i<s1;i++) f[1<<i]=1;
	for(int i=0;i<(1<<s1);i++)
		for(int j=0;j<s1;j++) if(!(i&(1<<j))) {
			int flag=1;
			for(int k=0;k<s1;k++)
				if(i&(1<<k)) flag&=mp[j][k];
			qmax(f[i|(1<<j)],f[i]+flag);
		}
	for(int i=0;i<s2;i++) g[1<<i]=1;
	for(int i=0;i<(1<<s2);i++)
		for(int j=0;j<s2;j++) if(!(i&(1<<j))) {
			int flag=1;
			for(int k=0;k<s2;k++)
				if(i&(1<<k)) flag&=mp[j+s1][k+s1];
			qmax(g[i|(1<<j)],g[i]+flag);
		}
	for(int i=0;i<(1<<s1);i++) {
		int flag=(1<<s2)-1;
		for(int j=0;j<s1;j++) if(i&(1<<j))
			for(int k=0;k<s2;k++) if(flag&(1<<k)&&!mp[j][k+s1])
				flag^=1<<k;
		qmax(ans,f[i]+g[flag]);
	}
	printf("%d\n",ans);
	return 0;
}


推荐阅读