1 6 8 1 2 1 3 2 4 2 5 3 4 3 6 4 6 5 6
3 1 4 5
此题不难看出,题目要求我们求出最大独立集,这里我们需要借助一个定理,那就是:一个图的最大团就是其补图的最大独立集,而一个图的最大独立集就是其补图的最大团。这个定理应该很好理解,一个团的所有点都是两两连接的,若取其补图,肯定是两两都没有连接。所以此题我们只需要在输入的时候建立其补图,然后套小编的最大团模板就搞定了。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=106; int g[maxn][maxn],dp[maxn],stk[maxn][maxn],mx; int path[maxn],res[maxn];//记录最大团的点 int dfs(int n,int ns,int dep)// { if(ns == 0) { if(dep > mx) { swap(path,res); mx = dep; return 1; } return 0; } int i,j,k,p,cnt; for(i=0; i<ns; i++) { k = stk[dep][i]; cnt = 0; if(dep + n - k <= mx) return 0;// 剪枝1, 若当前 顶点数量cnt 加上还能够增加的最大数量 仍小于 best则 退出并返回 if(dep + dp[k] <= mx) return 0;// 剪枝2, 若当前 顶点数量cnt 加上 包含adj[i]的最大团顶点数 仍小于 best则 退出并返回 for(j=i+1; j<ns; j++) { p = stk[dep][j]; if(g[k][p]) stk[dep+1][cnt++] = p; } path[dep+1] = k; if( dfs(n,cnt,dep+1) ) return 1; } return 0; } int clique(int n) { int i,j,ns; for(mx=0, i=n-1; i>=0; i--) { path[1] = i; for(ns=0, j=i+1; j<n; j++)// 遍历 [i+1, n] 间顶点 if(g[i][j]) stk[1][ns++] = j; dfs(n,ns,1); dp[i] = mx;// 得出顶点 i, 出发构成最大团 中顶点数量 } return mx; } int main() { int n,T,m; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); memset(g,1,sizeof(g)); for(int i=0; i<m; i++) { int x,y; scanf("%d%d",&x,&y); x--,y--; g[x][y] = g[y][x] = 0; } int ans = clique(n); printf("%d\n",ans); for(int i=1; i<=ans; i++) { printf("%d",res[i]+1); if(i == ans) printf("\n"); else printf(" "); } } return 0; }