最小路径覆盖:
即对于一个有向图来说选定最少的连通的路径(一条有向路径可以经过很多节点)使得图中每个节点均被覆盖。
做法为:将每一个节点拆成两个点,相连的节点在二分图上建边。最小路径覆盖数=n-最大匹配数。
POJ 1422
http://blog.csdn.net/x_1023/article/details/77151816(关于是否传递闭包的讨论)
POJ 2060
对于相邻的合法时刻建立有向路径,跑裸的最小路径覆盖。
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=505;
int n,q;
int t[maxn],match[maxn];
int x1[maxn],x2[maxn],y1[maxn],y2[maxn];
bool vst[maxn];
bool map[maxn][maxn];
bool judge(int i,int j)
{
int sum=abs(x1[i]-x2[i])+abs(y1[i]-y2[i])+abs(x2[i]-x1[j])+abs(y2[i]-y1[j]);
if(t[j]-t[i]>sum)return true;
return false;
}
bool find(int x)
{
for(int i=1;i<=n;i++)
{
if(!vst[i]&&map[x][i])
{
vst[i]=true;
if(!match[i]||find(match[i]))
{
match[i]=x;
return true;
}
}
}
return false;
}
int main()
{
scanf("%d",&q);
while(q--)
{
scanf("%d",&n);
memset(map,0,sizeof map);
memset(match+1,0,sizeof(int)*n);
for(int i=1;i<=n;i++)
{
int a,b;
scanf("%d:%d %d%d%d%d",&a,&b,x1+i,y1+i,x2+i,y2+i);
t[i]=a*60+b;
}
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
map[i][j]=judge(i,j);
int ans=0;
for(int i=1;i<=n;i++)
{
memset(vst+1,0,sizeof(bool)*n);
ans+=find(i);
}
printf("%d\n",n-ans);
}
}
最小点覆盖:
即对于一些二分图上的边,满足每个边两个节点中至少一个在一个点集合中,这个点集的元素最小个数。其值等于最大匹配数。
POJ 3041
对于每一个点,其行数和列数至少有一个被标记,则联系到最小点覆盖特性,将每个陨石点行数与列数相连建图即可。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=505;
const int maxm=10005;
struct edge
{
int to,next;
}e[maxm];
int n,m,T;
int vst[maxn];
int match[maxn];
int head[maxn];
inline void insert(int a,int b)
{
static int cnt=0;
e[++cnt].to=b;e[cnt].next=head[a];head[a]=cnt;
}
bool find(int x)
{
int y;
for(int i=head[x];i;i=e[i].next)
{
if(vst[y=e[i].to]==T)continue;
vst[y]=T;
if(!match[y]||find(match[y]))
{
match[y]=x;
return true;
}
}
return false;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
insert(a,b);
}
int ans=0;
for(int i=1;i<=n;i++)
{
T++;
ans+=find(i);
}
printf("%d",ans);
}
POJ 1325
对于给定的每一个项目,A machine进程和B machine进程至少选一个,则联系到最小点覆盖的特性,将A与B进程相连建图即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=1005;
struct edge
{
int to,next;
}e[maxn];
int n,m,k,T,cnt;
int head[maxn];
int match[maxn];
int vst[maxn];
inline void insert(int a,int b)
{
e[++cnt].to=b;e[cnt].next=head[a];head[a]=cnt;
}
void init()
{
cnt=0;
memset(head,0,sizeof head);
memset(match,0,sizeof match);
}
bool find(int x)
{
int y;
for(int i=head[x];i;i=e[i].next)
{
if(vst[y=e[i].to]==T)continue;
vst[y]=T;
if(!match[y]||find(match[y]))
{
match[y]=x;
return true;
}
}
return false;
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&k)&&n)
{
init();
for(int i=1;i<=k;i++)
{
int a,b;
scanf("%*d%d%d",&a,&b);
if(a&&b)//坑
insert(a,b);
}
int ans=0;
for(int i=1;i<=n;i++)
{
T++;
ans+=find(i);
}
printf("%d\n",ans);
}
return 0;
}
(待填坑......)