给定无向图G=(V,E),其中V是非空集合,称为顶点集;E是V中元素构成的无序二元组的集合,称为边集,无向图中的边均是顶点的无序对,无序对常用圆括号“( )”表示。如果U V,且对任意两个顶点u,v∈U有(u,v)∈E,则称U是G的完全子图。G的完全子图U是G的团。G的最大团是指G的最大完全子图
最大独立集:一个图中最大的互相没有边相连的点集
结论:原图的最大独立集等于补图的最大团(补图:图G的补图,通俗的来讲就是完全图Kn去除G的边集后得到的图Kn-G)
团的大小:点的权值和大小,并不是点的个数.
给定一个图,选择若干点涂成黑色,黑色的点之间不能有边相连,求最多涂几个黑点
解析:
即求最大独立集,即补图的最大团
二部图的最大独立集==顶点数-匹配数,普通图的最大独立集==补图的最大团
ac:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <queue>
#include <vector>
#define ll long long
#define MAXN 105
using namespace std;
int w[MAXN][MAXN];
int use[MAXN]; //进入团的标号
int bestx[MAXN];
int cn,bestn,p,e;
void dfs(int x)
{
bool flag;
if(x>p) {
bestn=cn; //cn的值是递增的
for( int i=1;i<=p; i++) //赋值给另外一个数组,
bestx[i]=use[i];
return ;
}
flag=true;
for( int i=1; i<x; i++)
if(use[i]&&!w[i][x]) {
flag=false;
break;
}
if(flag) {
cn++;
use[x]=true;
dfs(x+1);
cn--;
use[x]=false;//回溯
}
if(cn+p-x>bestn) { //剪枝
dfs(x+1);
}
}
int main()
{
int num,u,v;
scanf("%d",&num);
while(num--)
{
memset(w,1,sizeof(w));
memset(use,0,sizeof(use));
memset(bestx,0,sizeof(bestx));
scanf("%d%d",&p,&e);
for(int i=0; i<e; i++)
{
scanf("%d%d",&u,&v);
w[u][v]=0;
w[v][u]=0;
}
cn=bestn=0;
dfs(1);
printf("%d\n",bestn);//数目
for (int i=1; i<=p; i++)
{
if(bestx[i])
printf("%d ",i);
}
printf("\n");
}
return 0;
}
权值第K小的完全子图:
不懂,先存着
#include<bits/stdc++.h>
using namespace std;
int w[105];
bitset<105>Map[105];
char M[105][105];
struct ss
{
bitset<105>state;
long long w;
bool operator < (const ss & s)const
{
return w>s.w;
}
};
priority_queue<ss>q;
int n,k;
long long spfa(ss now)
{
q.push(now);
while(!q.empty())
{
now=q.top();
q.pop();
k--;
if(!k)
return now.w;
int pos=0;
for(int i=0;i<n;i++)
if(now.state[i])
pos=i+1;
for(int i=pos; i<n; i++)
{
if(now.state[i]==0)
{
if((now.state&Map[i])==now.state)//O(1)拓展新状态
{
now.state[i]=1;
now.w+=w[i];
q.push(now);
now.state[i]=0;
now.w-=w[i];
}
}
}
}
return -1;
}
int main()
{
scanf("%d %d",&n,&k);
for(int i=0; i<n; i++)
scanf("%d",&w[i]);
for(int i=0; i<n; i++)
scanf("%s",M[i]);
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
if(M[i][j]=='1')Map[i].set(j);
ss now;
now.state.reset();
now.w=0;
printf("%lld\n",spfa(now));
return 0;
}
最大团+dp优化:
#include<stdio.h>
#define MAXN 65
int mp[MAXN][MAXN];
int dp[MAXN],now[MAXN];
int n,Ans;
void DFS(int x ,int sum)
{
if(sum > Ans)
Ans = sum;
int able = 0;
int tnow[MAXN];
for(int i = x + 1 ;i <= n ;i ++)
{
tnow[i] = now[i];
if(now[i]) able ++;
}
if(able + sum <= Ans)
return;
for(int i = x + 1 ;i <= n ;i ++)
{
if(!tnow[i]) continue;
if(dp[i] + sum <= Ans) continue;
for(int j = x + 1 ;j <= n ;j ++)
now[j] = tnow[j] & mp[i][j];
DFS(i ,sum + 1);
}
}
int Max_Tuan()
{
Ans = dp[n] = 1;
for(int i = n - 1 ;i >= 1 ;i --)
{
for(int j = 1 ;j <= n ;j ++)
now[j] = mp[i][j];
DFS(i ,1);
dp[i] = Ans;
}
return Ans;
}
int main ()
{
int i ,j;
while(~scanf("%d",&n)&&n)
{
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
scanf("%d",&mp[i][j]);
}
}
printf("%d\n",Max_Tuan());
}
return 0;
}