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
浙公网安备 33010602011771号