几个二分图性质:
1. 最小点覆盖 等于 最大匹配,
最小点覆盖,实际上就是说选取最少的点,使得图中所有的边都与之相关联。
2. 最大独立集 等于 总点数 - 最小点覆盖。
最大独立集:就是选取一个最大的集合,使得集合的点之间,两两无对应边相连。
3.最小不相交路径覆盖 等于 顶点数 - 最大匹配。
最小边覆盖,在一个DAG中,选取最少的,顶点不相交的路径,覆盖图里所有的点。
过山车
模板,分析匈牙利算法,其实就是找得到就匹配,找不到这个点换一下看看能不能匹配;
#include<bits/stdc++.h> using namespace std; #define pb push_back const int N=6e2+5; vector<int>e[N]; int match[N]; bool vis[N]; bool findpath(int u){ for(int i=0;i<e[u].size();i++){ int v=e[u][i]; if(!vis[v]){ vis[v]=1; if(!match[v]||findpath(match[v])){ match[v]=u; return 1; } } } return 0; } int main(){ int k,m,n; while(~scanf("%d",&k),k){ scanf("%d %d",&m,&n); for(int i=0;i<=N;i++)match[i]=0,e[i].clear(); // girl.clear(); for(int i=1,u,v;i<=k;i++){ scanf("%d %d",&u,&v);e[u].pb(v); // girl.pb(u); } int ans=0; for(int i=1;i<=m;i++){ memset(vis,0,sizeof vis); if(findpath(i))ans++; } // cout<<"test"<<endl; printf("%d ",ans); } // system("pause"); return 0; }
Asteroids
题意:n*n的网格,有k个障碍,每次可以把某一行或者某一列删掉,求最小操作次数。
做法;对于给定的图,把每一行,每一列抽象为点,每一个障碍点(x,y),实际上可以抽象为 x 到 y 有一条边。
求最小操作次数,实际上就是求最小点覆盖。
#include<cstdio> #include<cstring> using namespace std; #define pb push_back typedef long long ll; const int inf=0x3f3f3f3f; typedef long long ll; typedef double db; const int N=5e2+50; int gp[N][N]; int match[N],vis[N]; int n,m,k; void init(){ memset(match,0,sizeof match); // memset(vis,0,sizeof vis); memset(gp,0,sizeof gp); } bool findpath(int u){ for(int i=1;i<=n;i++){ if(gp[u][i]&&!vis[i]){ vis[i]=1; if(!match[i]||findpath(match[i])){ match[i]=u; return 1; } } } return 0; } int main(){ init(); scanf("%d %d",&n,&k); for(int i=1,u,v;i<=k;i++){ scanf("%d %d",&u,&v); gp[u][v]=1; } int ans=0; for(int i=1;i<=n;i++){ memset(vis,0,sizeof vis); if(findpath(i))ans++; } // cout<<ans<<endl; printf("%d ",ans); // system("pause"); return 0; }
Air Raid
题意:一张图,求最小不相交路径覆盖,
#include<cstdio> #include<cstring> // #include<bits/stdc++.h> using namespace std; #define pb push_back typedef long long ll; const int inf=0x3f3f3f3f; typedef long long ll; typedef double db; const int N=5e2+50; int gp[N][N]; int match[N],vis[N]; int n,m,k; void init(){ memset(match,0,sizeof match); // memset(vis,0,sizeof vis); memset(gp,0,sizeof gp); } bool findpath(int u){ for(int i=1;i<=n;i++){ if(gp[u][i]&&!vis[i]){ vis[i]=1; if(!match[i]||findpath(match[i])){ match[i]=u; return 1; } } } return 0; } int main(){ int t; scanf("%d",&t); while(t--){ init(); scanf("%d %d",&n,&k); for(int i=1,u,v;i<=k;i++){ scanf("%d %d",&u,&v); gp[u][v]=1; } int ans=0; for(int i=1;i<=n;i++){ memset(vis,0,sizeof vis); if(findpath(i))ans++; } // cout<<ans<<endl; printf("%d ",n-ans); } // system("pause"); return 0; }
Guardian of Decency
一些男孩和女孩有暧昧关系,选出一个最大集,使得两两之间没有恋爱关系。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; #define pb push_back typedef long long ll; const int inf=0x3f3f3f3f; typedef long long ll; typedef double db; const int N=5e2+50; int gp[N][N],match[N],vis[N]; int n,m; void init(){ memset(gp,0,sizeof gp); memset(match,0,sizeof match); n=m=0; } struct node{ int h; string sex,mus,spo; }boy[N],girl[N]; bool check(node a,node b){ if(fabs(a.h-b.h)<=40&&a.sex!=b.sex&&a.mus==b.mus&&a.spo!=b.spo)return 1; return 0; } bool findpath(int u){ for(int i=1;i<=m;i++){ if(gp[u][i]&&!vis[i]){ vis[i]=1; if(!match[i]||findpath(match[i])){ match[i]=u; return 1; } } } return 0; } int main(){ int t,num; scanf("%d",&t); while(t--){ scanf("%d",&num); node tmp; init(); for(int i=1;i<=num;i++){ cin>>tmp.h>>tmp.sex>>tmp.mus>>tmp.spo; if(tmp.sex=="M")boy[++n]=tmp; else girl[++m]=tmp; } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(check(boy[i],girl[j]))gp[i][j]=1; } } int ans=0; for(int i=1;i<=n;i++){ memset(vis,0,sizeof vis); if(findpath(i))ans++; } printf("%d ",num-ans); } // system("pause"); return 0; }