最小路径覆盖:就是最少的变把所有的顶点全部覆盖,意思是删除最少的边把全部的点删除
最小路径覆盖=总节点数-最大匹配数。
最小点覆盖:选择最少的点 把路径全部覆盖 意思就是删除最少的点 可以把边全部删除
二分图的最小点覆盖=最大匹配数
给定一个有向无环图,要用若干条不相交简单路径覆盖所有顶点,求最少的路径条数。
算法分析:在有向无环图中,每条简单路径上有且仅有一个点没有后继。也就是说,每个没有后继的点就对应一条路径。要使路径条数最少,那么就是要没有后继的点的个数最少。
由于路径不相交,那么一个点最多有一个后继。转化一下,根据原图中的边建立二分图,左右各n个点。原图中有的边,就从左向右对应连边,代表它的所有可能后继。
那么问题就转化为最大二分匹配,匹配上的点就有后继,即可顺利解决。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
int flag[10][10];
int val[1002];
vector<int>vec[1002];
int match[1002];
int mate[1002];
bool vis[1002];
void Init()
{
memset(flag,0,sizeof(flag));
flag[0][1]=flag[0][7]=true;
flag[3][1]=flag[3][7]=true;
flag[4][1]=true;
flag[6][5]=true;
flag[7][1]=true;
for(int i=0;i<=7;i++)flag[8][i]=true;
flag[9][1]=flag[9][3]=flag[9][4]=flag[9][5]=flag[9][7]=flag[8][9]=true;
}
bool Find(int cur)
{
int len=vec[cur].size();
for(int i=0;i<len;i++)
{
int t=vec[cur][i];
if(vis[t]) continue;
vis[t]=true;
if(match[t]==0||Find(match[t]))
{
match[t]=cur;
mate[cur]=t;
return true;
}
}
return false;
}
int main()
{
int N;Init();
while(~scanf("%d",&N))
{
memset(match,0,sizeof(match));
memset(mate,0,sizeof(mate));
for(int i=1;i<=N;i++)
{
scanf("%d",&val[i]);
vec[i].clear();
}
for(int i=1;i<=N;i++)
for(int j=i+1;j<=N;j++)
if(flag[val[i]][val[j]])
vec[i].push_back(j);
int ans=0;
for(int i=1;i<=N;i++)
if(mate[i]==0)
{
memset(vis,0,sizeof(vis));
if(Find(i)) ans++;
}
printf("%d\n",N-ans);
}
return 0;
}