貌似咕了三个半月了(gym101915里一道),今天又遇到一道(cf1105E),就学了学惹。
最大团定义:图上取尽可能多的点,这些点构成一个完全图。
最大独立集:图上取尽可能多的点,任意两点间不连接。
可以看出来 一个图的最大团==它的补图的最大独立集 叭
那么我们可以搜索哇!(我不会搜索哇)
一个最朴素的搜索思想: 维护几个点集,当前已选择的,可以选择的,然后每次从可选择的点集里选一个与当前已选择的点都有边的点加进来,然后更新可选择的点集。
这个复杂度就比较恐怖哇
简单的优化:对点排序,每次都选一个节点编号比当前点编号大的。可以参考一下wannafly winter camp 的小木棍那题
剪枝一:如果当然已选点集大小+可选点集大小小于mx,return
剪枝二:我们从后向前选取点,保存后面的答案,如果当前点集+ans[待选]小于mx,return
其他的优化我也没看懂啊。。。
附 1105 E的代码,我真是自闭了。我傻逼了 map.count(s)和 mp[s] 是不一样的、、、调了半个多小时没看出来。。注释掉的部分是输出答案找bug的o.o
1 #include <bits/stdc++.h> 2 using namespace std; 3 map<string,int> mp; 4 int n,m,op;string s;int cnt=-1; 5 vector<int> v; 6 bool g[50][50]; 7 int ans;int mx[50];int alt[50][50]; 8 //int cs[50]; 9 bool DFS(int cur, int tot) { 10 if(cur==0) { 11 if(tot>ans) { 12 ans=tot; 13 //for(int i=0;i<tot;i++){ 14 // cout<<cs[i]<<' '; 15 //} 16 //cout<<endl; 17 return 1; 18 } 19 return 0; 20 } 21 for(int i=0; i<cur; i++) { 22 if(cur-i+tot<=ans) return 0; 23 int u=alt[tot][i]; 24 if(mx[u]+tot<=ans) return 0; 25 int nxt=0;//cs[tot]=u; 26 for(int j=i+1; j<cur; j++) 27 if(g[u][alt[tot][j]]) 28 alt[tot+1][nxt++]=alt[tot][j]; 29 if(DFS(nxt, tot+1)) return 1; 30 } 31 return 0; 32 } 33 int MaxClique() { 34 for(int i=cnt;i>=0; i--) { 35 //cs[0]=i; 36 int cur=0; 37 for(int j=i+1; j<=cnt; j++) 38 if(g[i][j]) 39 alt[1][cur++]=j; 40 DFS(cur, 1); 41 mx[i]=ans; 42 } 43 return ans; 44 } 45 int main(){ 46 ios::sync_with_stdio(false); 47 memset(g,1, sizeof(g)); 48 cin>>n>>m; 49 for(int i=1;i<=n;i++){ 50 cin>>op; 51 if(op==1) v.clear(); 52 else{ 53 cin>>s; 54 if(!mp.count(s))mp[s]=++cnt; 55 int tmp = mp[s]; 56 for(auto q:v) 57 g[tmp][q]=g[q][tmp]=false; 58 v.push_back(tmp); 59 } 60 } 61 cout<<MaxClique()<<endl; 62 }