2021.11.02 最小支配集、最小点覆盖、最大独立集

前置知识

最小支配集:选取一个点集,使得剩余的点都与这个集合有边相连,则称这个集合为支配集。如果在点集中去掉一个点而是这个集合不是一个支配集,那么这个集合是一个最小支配集,点集中的点的个数支配数。

最小点覆盖:选取一个点集,使得所有边都与这个集合相连,则称这个集合为点覆盖。也就是说对于任意一条边(u,v),u,v中至少有一个点在集合中。如果在点集中去掉一个点而是这个集合不是一个点覆盖,那么这个集合是一个最小点覆盖,点集中的点的个数为最小点覆盖数。

最大独立集:选取一个点集,使得点集中的点没有边相连,这就是一个独立集。对于一个点集,若添加任意一个点都能使它不是独立集就说这个点集为最大独立集。

——来自求最小支配集,最小点覆盖,最大独立集 - lxykk - 博客园 (cnblogs.com)

最小支配集

[P2458 SDOI2006]保安站岗 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=1510;
int n,cnt,head[N],f[N][5];
struct node{
	int to,next;
}a[N*2];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void add(int u,int v){
	++cnt;
	a[cnt].to=v;
	a[cnt].next=head[u];
	head[u]=cnt;
}
inline void dfs(int x,int fai){
	//f[x][2]=1;//0 son 1 fa 2 myself
	int minn=0x7fffffff;
	for(int i=head[x];i;i=a[i].next){
		int v=a[i].to;
		if(v==fai)continue;
		dfs(v,x);
		f[x][0]+=min(f[v][0],f[v][2]);
		f[x][1]+=min(f[v][0],f[v][2]);
		f[x][2]+=min(f[v][0],min(f[v][1],f[v][2]));
		minn=min(minn,f[v][2]-min(f[v][0],f[v][2]));
	}
	f[x][0]+=minn;
}

int main(){
	n=read();
	for(register int i=1;i<=n;i++){
		int u,v,k;
		u=read();
		f[u][2]=read();
		k=read();
		for(register int j=1;j<=k;j++)
		v=read(),add(u,v),add(v,u);
	}
	dfs(1,0);
	cout<<min(f[1][0],f[1][2]);
	return 0;
}

[P2899 USACO08JAN]Cell Phone Network G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=1e4+10;
int n,cnt,head[N],f[N][5];
struct node{
	int to,next;
}a[N*2];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void add(int u,int v){
	++cnt;
	a[cnt].to=v;
	a[cnt].next=head[u];
	head[u]=cnt;
}
inline void dfs(int x,int fai){
	f[x][2]=1;//0 son 1 fa 2 myself
	int minn=0x7fffffff;
	for(int i=head[x];i;i=a[i].next){
		int v=a[i].to;
		if(v==fai)continue;
		dfs(v,x);
		f[x][0]+=min(f[v][0],f[v][2]);
		f[x][1]+=min(f[v][0],f[v][2]);
		f[x][2]+=min(f[v][0],min(f[v][1],f[v][2]));
		minn=min(minn,f[v][2]-min(f[v][0],f[v][2]));
	}
	f[x][0]+=minn;
}

int main(){
	n=read();
	for(register int i=1;i<n;i++){
		int u,v;
		u=read();v=read();
		add(u,v);add(v,u);
	}
	dfs(1,0);
	cout<<min(f[1][0],f[1][2]);
	return 0;
}

最小点覆盖

UVA1292 Strategic game - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=1510;
int n,cnt,head[N],f[N][2];
struct node{
	int to,next;
}a[N*2];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void add(int u,int v){
	++cnt;
	a[cnt].to=v;
	a[cnt].next=head[u];
	head[u]=cnt;
}
void dfs(int x,int fa){
	f[x][1]=1;
	for(register int i=head[x];i;i=a[i].next){
		int v=a[i].to;
		if(v==fa)continue;
		dfs(v,x);
		f[x][0]+=f[v][1];
		f[x][1]+=min(f[v][0],f[v][1]);
	}
}

int main(){
	while(~scanf("%d",&n)){
	cnt=0;
	memset(f,0,sizeof(f));
	memset(head,0,sizeof(head));
	//cout<<n<<endl;
	for(register int i=1;i<=n;i++){
		int u,x;
		u=read()+1;
		x=read();
		for(register int j=1;j<=x;j++){
			int v=read()+1;
			add(u,v);add(v,u);
			//cout<<u<<" "<<v<<endl;
		}
	}
	dfs(1,0);
	cout<<min(f[1][1],f[1][0])<<endl;
	}
	return 0;
}

P2016 战略游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=1510;
int n,cnt,head[N],f[N][2];
struct node{
	int to,next;
}a[N*2];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void add(int u,int v){
	++cnt;
	a[cnt].to=v;
	a[cnt].next=head[u];
	head[u]=cnt;
}
void dfs(int x,int fa){
	f[x][1]=1;
	for(register int i=head[x];i;i=a[i].next){
		int v=a[i].to;
		if(v==fa)continue;
		dfs(v,x);
		f[x][0]+=f[v][1];
		f[x][1]+=min(f[v][0],f[v][1]);
	}
}

int main(){
	n=read();
	for(register int i=1;i<=n;i++){
		int u,x;
		u=read()+1;
		x=read();
		for(register int j=1;j<=x;j++){
			int v=read()+1;
			add(u,v);add(v,u);
			//cout<<u<<" "<<v<<endl;
		}
	}
	dfs(1,0);
	cout<<min(f[1][1],f[1][0]);
	return 0;
}

[P7368 USACO05NOV]Asteroids G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

二分图匹配的最小点覆盖

König 定理:

一个二分图中的最大匹配数等于这个图中的最小点覆盖数。

二分图最大匹配的König定理及其证明 | Matrix67: The Aha Moments

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=510;
int n,m,a[N][N],link[N],vis[N];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline int dfs(int x){
	for(int i=1;i<=n;i++){
		if(i==x||!a[x][i])continue;
		if(vis[i])continue;
		vis[i]=1;
		if(!link[i]||dfs(link[i]))return link[i]=x,1;
	}
	return 0;
} 
inline int xiongyali(){
	int ans=0;
	for(int i=1;i<=n;i++){
		memset(vis,0,sizeof(vis));
		if(dfs(i))++ans;
	}
	return ans;
}

int main(){
	n=read();m=read();
	for(int i=1;i<=m;i++){
		int u,v;
		u=read();v=read();
		a[u][v]=1;
	}
	cout<<xiongyali();
	return 0;
}

网络流写法:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;

const int N=1010;
int n,m,cnt=1,head[N],start,endi,vis[N],cur[N],dep[N];
struct node{
	int to,next,val;
}a[600010];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void addi(int u,int v,int w){
	++cnt;
	a[cnt].to=v;
	a[cnt].val=w;
	a[cnt].next=head[u];
	head[u]=cnt;
}
inline void add(int u,int v,int w){
	addi(u,v,w);addi(v,u,0);
}
inline int bfs(int s,int t){
	memset(dep,0,sizeof(dep));
	memcpy(cur,head,sizeof(head));
	queue<int>q;
	q.push(s);
	dep[s]=1;
	while(!q.empty()){
		int x=q.front();q.pop();
		for(int i=head[x];i;i=a[i].next){
			int v=a[i].to;
			if(a[i].val&&!dep[v])dep[v]=dep[x]+1,q.push(v);
		}
	}
	return dep[t];
}
inline int dfs(int x,int t,int f){
	if(x==t)return f;
	int ans=0;
	for(int i=cur[x];i&&ans<f;i=a[i].next){
		cur[x]=i;
		int v=a[i].to;
		int fi=0;
		if(a[i].val&&dep[v]==dep[x]+1&&(fi=dfs(v,t,min(a[i].val,f-ans)))>0)
		a[i].val-=fi,a[i^1].val+=fi,ans+=fi;
	}
	return ans;
}
inline int dinic(int s,int t){
	int flow=0;
	while(bfs(s,t)){
		//cout<<"    Case 1"<<endl;
		int x=0;
		if((x=dfs(s,t,1<<30))>0)flow+=x;
	}
	return flow;
}

int main(){
	n=read();m=read();
	for(int i=1;i<=m;i++){
		int u,v;
		u=read();v=read()+n;
		add(u,v,1<<30);
	}
	endi=n*2+2;start=n*2+1;
	for(int i=1;i<=n;i++)add(start,i,1),add(i+n,endi,1);
	cout<<dinic(start,endi);
	return 0;
}

最大独立集

二分图最大独立集 = 总点数 - 最小点覆盖 = 总点数 - 最大匹配

[P6268 SHOI2002]舞会 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=2010;
int n,m,cnt,head[N],link[N],vis[N];
struct node{
	int to,next;
}a[N*2];

inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
inline void add(int u,int v){
	++cnt;
	a[cnt].to=v;
	a[cnt].next=head[u];
	head[u]=cnt;
}
inline int dfs(int x){
	for(int i=head[x];i;i=a[i].next){
		int v=a[i].to;
		if(vis[v])continue;
		vis[v]=1;
		if(!link[v]||dfs(link[v])){
			link[v]=x;
			return 1;
		}
	}
	return 0;
}
inline int xiongyali(){
	int ans=0;
	for(int i=1;i<=n;i++){
		memset(vis,0,sizeof(vis));
		if(dfs(i))++ans;
	}
	return ans;
}

int main(){
	n=read();m=read();
	for(int i=1;i<=m;i++){
		int u,v;
		u=read()+1;v=read()+1;
		add(u,v);add(v,u);
	}
	cout<<n-xiongyali()/2;
	return 0;
}
 posted on 2021-11-03 16:08  eleveni  阅读(241)  评论(0)    收藏  举报