您的位置:首页 > 其它

UVA-1201 - Taxi Cab Scheme(POJ-2060)--DAG的最小路径覆盖

2013-03-01 21:18 302 查看
刘汝佳新书--训练指南

本题中时间是一个天然的序,因此可以构图如下:每个客人是一个点,如果同一个出租车在接完客人u以后来得及接客人v,连边u->v。不难发现这个图是一个DAG,并且它的最小路径覆盖就是本题的答案。

最小路径覆盖=结点数-最大匹配数

证明:

DAG最小路径覆盖的解法如下:把所有结点i拆成X结点i和Y结点i',如果图G中存在有向边i->j,则在二分图中引入边i->j'。设二分图的最大匹配数为m,则结果就是n-m。

为什么呢?因为匹配和路径覆盖是一一对应的。对于路径覆盖中的每条简单路径,除了最后一个“结尾结点”之外都有唯一的后继和它对应(即匹配结点),因此匹配数就是非尾结点的个数。当匹配数达到最大时,非尾结点的个数也将达到最大。此时,结尾结点的个数最少,即路径条数最少。

// File Name: 1201.cpp
// Author: zlbing
// Created Time: 2013/3/1 20:40:52

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define CL(x,v); memset(x,v,sizeof(x));
#define INF 0x3f3f3f3f
#define LL long long
#define MAXN 505
int Left[MAXN];//Left[i]为左边与右边第i个点匹配的编号
int w[MAXN][MAXN];
bool S[MAXN],T[MAXN];
int N;
struct Point{
int t,a,b,c,d;
}cust[MAXN];
bool match(int i)
{
S[i]=true;
for(int j=1;j<=N;j++)if(w[i][j]&&!T[j])
{
T[j]=true;
if(Left[j]==0||match(Left[j]))
{
Left[j]=i;
return true;
}
}
return false;
}

//返回的是最大匹配数

int hungry(){
CL(Left,0);
int sum=0;
for(int i=1;i<=N;i++)
{
CL(S,0);
CL(T,0);
if(match(i))sum++;
}
return sum;
}
int count1(Point p)
{
return abs(p.a-p.c)+abs(p.b-p.d);
}
int count2(Point p1,Point p2)
{
return abs(p2.a-p1.c)+abs(p2.b-p1.d);
}

int main(){
int cas=0;
scanf("%d",&cas);
while(cas--)
{
scanf("%d",&N);
for(int i=1;i<=N;i++)
{
int t,tt,a,b,c,d;
scanf("%d:%d %d %d %d %d",&t,&tt,&a,&b,&c,&d);
tt+=t*60;
cust[i].t=tt,cust[i].a=a,cust[i].b=b,cust[i].c=c,cust[i].d=d;
}
CL(w,0);
for(int i=1;i<=N;i++)
for(int j=i+1;j<=N;j++)
{
if(cust[i].t+count1(cust[i])+count2(cust[i],cust[j])<cust[j].t)
w[i][j]=1;
}
int ans=hungry();
printf("%d\n",N-ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: