最小路径覆盖:在一个PXP的有向图中,路径覆盖就是在图中找一些路经,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联;(如果把这些路径中的每条路径从它的起始点走到它的终点,那么恰好可以经过图中的每个顶点一次且仅一次);如果不考虑图中存在回路,那么每每条路径就是一个弱连通子集.
由上面可以得出:
1.一个单独的顶点是一条路径;
2.如果存在一路径p1,p2,......pk,其中p1 为起点,pk为终点,那么在覆盖图中,顶点p1,p2,......pk不再与其它的顶点之间存在有向边.
最小路径覆盖就是找出最小的路径条数,使之成为P的一个路径覆盖.
路径覆盖与二分图匹配的关系(必须是没有圈的有向图):
最小路径覆盖=|P|-最大匹配数;
故装化为二分匹配:
#include<iostream>
#include<cmath>
using namespace std;
const int N = 505 ;
struct Node
{
int time1,time2;
int fromx,fromy,tox,toy;
}Edge[N];
int n,map[N][N],match[N],link[N];
bool find(int i)
{
for(int j=1;j<=n;j++)
{
if(!match[j]&&map[i][j])
{
match[j]=1;
if(link[j]==-1||find(link[j]))
{
link[j]=i;
return true;
}
}
}
return false;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
char s[10];
for(int i=1;i<=n;i++)
{
scanf("%s",&s);
Edge[i].time1 = ((s[0]-'0')*10+(s[1]-'0'))*60+(s[3]-'0')*10+(s[4]-'0');
scanf("%d%d%d%d",&Edge[i].fromx,&Edge[i].fromy,&Edge[i].tox,&Edge[i].toy);
int tmp = abs(Edge[i].fromx-Edge[i].tox)+abs(Edge[i].fromy-Edge[i].toy);
Edge[i].time2 = Edge[i].time1+tmp;
}
memset(map,0,sizeof(map));
memset(link,-1,sizeof(link));
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
{
int tmp = abs(Edge[i].tox-Edge[j].fromx)+abs(Edge[i].toy-Edge[j].fromy);
if(Edge[i].time2 + tmp< Edge[j].time1) map[i][j] = 1;
}
int ans=0;
for(int i=1;i<=n;i++)
{
memset(match,0,sizeof(match));
if(find(i)) ans++;
}
cout<<n-ans<<endl;
}
return 0;
}