最小路径覆盖:
一个PXP的有向图中,路径覆盖就是在图中找一些路径,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联;(如果把这些路径中的每条路径从它的起始点走到它的终点,那么恰好可以经过图中的每个顶点一次且仅一次);如果不考虑图中存在回路,那么每条路径就是一个弱连通子集.
由上面可以得出:
1.一个单独的顶点是一条路径;
2.如果存在一路径p1,p2,......pk,其中p1 为起点,pk为终点,那么在覆盖图中,顶点p1,p2,......pk不再与其它的顶点之间存在有向边.
最小路径覆盖就是找出最小的路径条数,使之成为P的一个路径覆盖.
路径覆盖与二分图匹配的关系(必须是没有圈的有向图):
最小路径覆盖=|P|-其中最大匹配数的求法是
把P中的每个顶点pi分成两个顶点pi'与pj
'',如果在p中存在一条pi到pj的边,那么在二分图P'中就有一条连接pi'与pj''的无向边;这里pi' 就是p中pi的出边,pj''就是p中pj 的一条入边;
对于公式:
最小路径覆盖=|P|-最大匹配数;可以这么来理解;
如果匹配数为零,那么P中不存在有向边,于是显然有:
最小路径覆盖=|P|-最大匹配数=|P|-0=|P|;即P的最小路径覆盖数为|P|;
P'中不在于匹配边时,路径覆盖数为|P|;
如果在P'中增加一条匹配边pi'-->pj'',那么在图P的路径覆盖中就存在一条由pi连接pj的边,也就是说pi与pj 在一条路径上,于是路径覆盖数就可以减少一个;
如此继续增加匹配边,每增加一条,路径覆盖数就减少一条;直到匹配边不能继续增加时,路径覆盖数也不能再减少了,此时就有了前面的公式;但是这里只 是说明了
每条匹配边对应于路径覆盖中的一条路径上的一条连接两个点之间的有向边;
思路:拆点+最大二分匹配
代码:
#include<iostream>
#include<iostream>
#include<string.h>
using namespace std;
#define N 505
struct str
{ int wi;
int li;
int hi;
}a[N];
typedef struct str1
{ int to;
int next;
}Node;
Node node[N*100 ];
int head[N];
bool flag[N];
int match[N];
int n,tot;
void init()
{ memset(head,-1,sizeof(head));
memset(match,-1,sizeof(match));
for(int i=1;i<=n;++i)
cin>>a[i].wi>>a[i].li>>a[i].hi;
tot=0;
}
void add(int a,int b)
{ node[tot].to=b;
node[tot].next=head[a];
head[a]=tot++;
}
bool dfs(int i)
{
for(int j=head[i];j!=-1;j=node[j].next)
{ int v=node[j].to;
if(!flag[v])
{
flag[v]=true;
if(match[v]==-1||dfs(match[v]))
{ match[v]=i;
return true;
}
}
}
return false;
}
int main()
{ while(cin>>n&&n)
{ init();
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(a[i].hi<a[j].hi&&a[i].li<a[j].li&&a[i].wi<a[j].wi)
add(i,j);
int sum=0;
for(int i=1;i<=n;++i)
{ memset(flag,false,sizeof(flag));
if(dfs(i))
sum++;
}
cout<<n-sum<<endl;
}return 0;
}