POJ-2060-Taxi Cab Scheme-最小路径覆盖

http://poj.org/problem?id=2060

题意:有n个任务:开始时间、起始地点、终止地点。每个地点可以派出一辆出租车,如果出租车完成任务i后还可以到达任务j,那么它可以继续执行任务j。现在问最少可以排除多少辆出租车?


乍一看,像是最小路径的问题,关键有个地方是,即使任务A的终点和任务B的起点相同,也不代表路径A-B合法,还要判断:任务i的开始时间+任务i的完成时间+从任务i的目的地到达任务j的起始地点所花费的时间<任务j的开始时间


因此建图的话,得以任务为点,如果任务B能接着任务B继续作,就在他们之间连一条边。显然,这样建图的话,每一条路径只需要一辆车就能走完,因此题目求最少车辆完成任务,转化成了  最后求最少路径数,覆盖所有任务点


此二分图的两部分点集,都是n个任务,因为任务是按时间递增排序的,所以与任务【i】连边只需要j>i部分的任务【j】即可

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;

const double pi=acos(-1.0);
double eps=0.000001;  

//顶点编号从0开始的
const int MAXN = 510;
int uN,vN;//u,v的数目,使用前面必须赋值
int g[MAXN][MAXN];//邻接矩阵
int linker[MAXN];
bool used[MAXN];
bool dfs(int u)
{
	for(int v = 0; v < vN;v++)
		if(g[u][v] && !used[v])
		{
			used[v] = true;
			if(linker[v] == -1 || dfs(linker[v]))
			{
				linker[v] = u;
				return true;
			}
		}
		return false;
} 
int hungary()
{
	int res = 0;  
	memset(linker,-1,sizeof(linker));
	for(int u = 0;u < uN;u++)
	{ 
		memset(used,false,sizeof(used));
		if(dfs(u))res++;
	}
	return res;
} 
int t1[505],t2[505];
int a[505],b[505],c[505],d[505];
int dis(int i,int j)
{
	int tt1=t1[i]*60+t2[i];
	int tt2=t1[j]*60+t2[j];
	return tt2-tt1;
}
int main()
{
	int i,j; 
	int t;cin>>t;
	while(t--)
	{
		memset(g,0,sizeof(g));
		int n;
		cin>>n;
		for (i=0;i<n;i++) 
			scanf("%d:%d %d %d %d %d",&t1[i],&t2[i],&a[i],&b[i],&c[i],&d[i]);
	
		for (i=0;i<n;i++) 
		{
			for (j=i+1;j<n;j++)
			{
			 	int need=abs(c[i]-a[j])+abs(d[i]-b[j])+1+abs(c[i]-a[i])+abs(b[i]-d[i]);
				int has=dis(i,j);
				if (has>=need) 
				 g[i][j]=1; 
			}
		}
		uN=vN=n;
		int ret=hungary();
		//最小路径覆盖=最大独立集=n-最大匹配数
		printf("%d\n",n-ret );
	}
	
	
	return 0;
	
}


你可能感兴趣的:(POJ-2060-Taxi Cab Scheme-最小路径覆盖)