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; }