POJ2060 Taxi Cab Scheme [最小路径覆盖]
2011-08-18 14:16
363 查看
转载的文章:
根据这道题目的意思,我们可以建一张图,对于两个booked taxi ride,ri和rj如果一辆车能够先完成ri的任务再有时间赶去完成rj的任务,那么就建立一条ri指向rj的边。
![](http://www.cppblog.com/images/cppblog_com/linyangfei/1.JPG)
按照题目的要求,要选择最少的taxi来完成这些任务。显然在上面这个例子中,需要安排2辆taxi。结合这个图,可以把题目的要求转化为找出最少的路径条数,使得这些路径覆盖途中所有的边,例如可以选择2条路径1->3->4和1->2就可以覆盖所有的边。也可以选择1->3->4和2(因为2作为初始站,不需要由1转移过来)。对于一条连续的路径vi1->vi2->…vik由于这条路径上的任务实际上是由一辆taxi来完成的,可以把这条路径退化成两个点vi1->vik。有了这两步建图的步骤以后,问题的求解就可以变为找出顶点集的一个最小子集,使这个顶点子集覆盖所有的边(每条边都至少和一个顶点集的顶点相连)。这个问题就是图的最小点覆盖。再看这张图,还有一些性质能够让我们更好地求出最小点覆盖。这个图是一个有向无环图,没有自环,就可以拆点,把原先建的图变成一张二分图。
![](http://www.cppblog.com/images/cppblog_com/linyangfei/2.JPG)
可以再图中看出,上面举出的一条路径1->3->4对应了这个二分图中的路径1->
3’->3->4’,在这个二分图中就需要求一个最大独立子集(这里的4点就是一条路径的终点,每一条路径即对应有一个终点!)。二分图的最大独立数是总点数与最大匹配数的差值。接下来建图,拆点,求二分图最大匹配就能解决这道题目了。
老实说,刚接触二分图,这道题完全是参考别人的代码和思路:
#include<iostream>
#include<cmath>
using namespace std;
int n;
const int N=505;
struct
{
int sta,end,a,b,c,d;
}r
;
int edgeHead
,link
;
bool visit
;
struct
{
int v;
int next;
}edge[N*N];
bool dfs(int v)
{
for(int i=edgeHead[v];i!=0;i=edge[i].next)
{
int now=edge[i].v;
if(!visit[now])
{
visit[now]=true;
if(link[now]==0||dfs(link[now]))
{
link[now]=v;
return true;
}
}
}
return false;
}
int main()
{
//freopen("C:\\Users\\wuyanyisb\\Desktop\\1.txt","r",stdin);
int cases;
scanf("%d",&cases);
while(cases--)
{
int h,m,k=1;
memset(edge,0,sizeof(edge));
memset(edgeHead,0,sizeof(edgeHead));
memset(link,0,sizeof(link));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d:%d",&h,&m);
scanf("%d%d%d%d",&r[i].a,&r[i].b,&r[i].c,&r[i].d);
r[i].sta=60*h+m;
r[i].end = r[i].sta + abs(r[i].a-r[i].c) + abs(r[i].b-r[i].d);
for(int j=i-1;j>=1;j--)
{
if(r[i].sta >= r[j].end + abs(r[i].a-r[j].c) + abs(r[i].b-r[j].d) + 1)
{
edge[k].v = j;
edge[k].next = edgeHead[i];
edgeHead[i] = k ++;
}
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
memset(visit,0,sizeof(visit));
if(dfs(i))
ans++;
}
printf("%d\n",n-ans);
}
return 0;
}
一直很不擅长连接表的图表示。
下面是连接矩阵的代码。下面代码运行时间600MS+
上面代码运行时间200MS+
#include<iostream>
#include<cmath>
using namespace std;
int n;
const int N=505;
struct
{
int sta,end,a,b,c,d;
}r
;
int edgeHead
,link
;
bool visit
;
struct
{
int v;
int next;
}edge[N*N];
bool mat
;
bool dfs(int v)
{
/*for(int i=edgeHead[v];i!=0;i=edge[i].next)
{
int now=edge[i].v;
if(!visit[now])
{
visit[now]=true;
if(link[now]==0||dfs(link[now]))
{
link[now]=v;
return true;
}
}
}
return false;*/
for(int i=1;i<=n;i++)
{
if(mat[v][i]&&!visit[i])
{
visit[i]=true;
if(link[i]==0||dfs(link[i]))
{
link[i]=v;
return true;
}
}
}
return false;
}
int main()
{
//freopen("C:\\Users\\wuyanyisb\\Desktop\\1.txt","r",stdin);
int cases;
scanf("%d",&cases);
while(cases--)
{
int h,m,k=1;
//memset(edge,0,sizeof(edge));
//memset(edgeHead,0,sizeof(edgeHead));
memset(mat,0,sizeof(mat));
memset(link,0,sizeof(link));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d:%d",&h,&m);
scanf("%d%d%d%d",&r[i].a,&r[i].b,&r[i].c,&r[i].d);
r[i].sta=60*h+m;
r[i].end = r[i].sta + abs(r[i].a-r[i].c) + abs(r[i].b-r[i].d);
for(int j=i-1;j>=1;j--)
{
if(r[i].sta >= r[j].end + abs(r[i].a-r[j].c) + abs(r[i].b-r[j].d) + 1)
{
/* edge[k].v = j;
edge[k].next = edgeHead[i];
edgeHead[i] = k ++;
*/
mat[i][j]=true;
}
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
memset(visit,0,sizeof(visit));
if(dfs(i))
ans++;
}
printf("%d\n",n-ans);
}
return 0;
}
根据这道题目的意思,我们可以建一张图,对于两个booked taxi ride,ri和rj如果一辆车能够先完成ri的任务再有时间赶去完成rj的任务,那么就建立一条ri指向rj的边。
按照题目的要求,要选择最少的taxi来完成这些任务。显然在上面这个例子中,需要安排2辆taxi。结合这个图,可以把题目的要求转化为找出最少的路径条数,使得这些路径覆盖途中所有的边,例如可以选择2条路径1->3->4和1->2就可以覆盖所有的边。也可以选择1->3->4和2(因为2作为初始站,不需要由1转移过来)。对于一条连续的路径vi1->vi2->…vik由于这条路径上的任务实际上是由一辆taxi来完成的,可以把这条路径退化成两个点vi1->vik。有了这两步建图的步骤以后,问题的求解就可以变为找出顶点集的一个最小子集,使这个顶点子集覆盖所有的边(每条边都至少和一个顶点集的顶点相连)。这个问题就是图的最小点覆盖。再看这张图,还有一些性质能够让我们更好地求出最小点覆盖。这个图是一个有向无环图,没有自环,就可以拆点,把原先建的图变成一张二分图。
可以再图中看出,上面举出的一条路径1->3->4对应了这个二分图中的路径1->
3’->3->4’,在这个二分图中就需要求一个最大独立子集(这里的4点就是一条路径的终点,每一条路径即对应有一个终点!)。二分图的最大独立数是总点数与最大匹配数的差值。接下来建图,拆点,求二分图最大匹配就能解决这道题目了。
老实说,刚接触二分图,这道题完全是参考别人的代码和思路:
#include<iostream>
#include<cmath>
using namespace std;
int n;
const int N=505;
struct
{
int sta,end,a,b,c,d;
}r
;
int edgeHead
,link
;
bool visit
;
struct
{
int v;
int next;
}edge[N*N];
bool dfs(int v)
{
for(int i=edgeHead[v];i!=0;i=edge[i].next)
{
int now=edge[i].v;
if(!visit[now])
{
visit[now]=true;
if(link[now]==0||dfs(link[now]))
{
link[now]=v;
return true;
}
}
}
return false;
}
int main()
{
//freopen("C:\\Users\\wuyanyisb\\Desktop\\1.txt","r",stdin);
int cases;
scanf("%d",&cases);
while(cases--)
{
int h,m,k=1;
memset(edge,0,sizeof(edge));
memset(edgeHead,0,sizeof(edgeHead));
memset(link,0,sizeof(link));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d:%d",&h,&m);
scanf("%d%d%d%d",&r[i].a,&r[i].b,&r[i].c,&r[i].d);
r[i].sta=60*h+m;
r[i].end = r[i].sta + abs(r[i].a-r[i].c) + abs(r[i].b-r[i].d);
for(int j=i-1;j>=1;j--)
{
if(r[i].sta >= r[j].end + abs(r[i].a-r[j].c) + abs(r[i].b-r[j].d) + 1)
{
edge[k].v = j;
edge[k].next = edgeHead[i];
edgeHead[i] = k ++;
}
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
memset(visit,0,sizeof(visit));
if(dfs(i))
ans++;
}
printf("%d\n",n-ans);
}
return 0;
}
一直很不擅长连接表的图表示。
下面是连接矩阵的代码。下面代码运行时间600MS+
上面代码运行时间200MS+
#include<iostream>
#include<cmath>
using namespace std;
int n;
const int N=505;
struct
{
int sta,end,a,b,c,d;
}r
;
int edgeHead
,link
;
bool visit
;
struct
{
int v;
int next;
}edge[N*N];
bool mat
;
bool dfs(int v)
{
/*for(int i=edgeHead[v];i!=0;i=edge[i].next)
{
int now=edge[i].v;
if(!visit[now])
{
visit[now]=true;
if(link[now]==0||dfs(link[now]))
{
link[now]=v;
return true;
}
}
}
return false;*/
for(int i=1;i<=n;i++)
{
if(mat[v][i]&&!visit[i])
{
visit[i]=true;
if(link[i]==0||dfs(link[i]))
{
link[i]=v;
return true;
}
}
}
return false;
}
int main()
{
//freopen("C:\\Users\\wuyanyisb\\Desktop\\1.txt","r",stdin);
int cases;
scanf("%d",&cases);
while(cases--)
{
int h,m,k=1;
//memset(edge,0,sizeof(edge));
//memset(edgeHead,0,sizeof(edgeHead));
memset(mat,0,sizeof(mat));
memset(link,0,sizeof(link));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d:%d",&h,&m);
scanf("%d%d%d%d",&r[i].a,&r[i].b,&r[i].c,&r[i].d);
r[i].sta=60*h+m;
r[i].end = r[i].sta + abs(r[i].a-r[i].c) + abs(r[i].b-r[i].d);
for(int j=i-1;j>=1;j--)
{
if(r[i].sta >= r[j].end + abs(r[i].a-r[j].c) + abs(r[i].b-r[j].d) + 1)
{
/* edge[k].v = j;
edge[k].next = edgeHead[i];
edgeHead[i] = k ++;
*/
mat[i][j]=true;
}
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
memset(visit,0,sizeof(visit));
if(dfs(i))
ans++;
}
printf("%d\n",n-ans);
}
return 0;
}
相关文章推荐
- POJ-2060 Taxi Cab Scheme 最小路径覆盖
- 二分图最小路径覆盖--poj2060 Taxi Cab Scheme
- poj 2060 Taxi Cab Scheme(DAG图的最小路径覆盖)
- poj2060 Taxi Cab Scheme 最小路径覆盖=顶点数-最大匹配数
- Poj-2060 Taxi Cab Scheme 二分图最小路径覆盖
- POJ_2060_Taxi Cab Scheme【最小路径覆盖】
- POJ:2060-Taxi Cab Scheme(最小路径覆盖)
- POJ-2060-Taxi Cab Scheme-最小路径覆盖
- POJ2060 Taxi Cab Scheme【二分图最小路径覆盖】
- POJ 2060 Taxi Cab Scheme DAG最小路径覆盖
- UVA-1201 - Taxi Cab Scheme(POJ-2060)--DAG的最小路径覆盖
- POJ 2060 Taxi Cab Scheme(最小路径覆盖)
- POJ 2060 Taxi Cab Scheme【最小路径覆盖】
- HDU 1350 & HDU 1960 & POJ 2060 Taxi Cab Scheme【二分图之最小路径覆盖,经典】
- POJ 2060 Taxi Cab Scheme【最小路径覆盖】
- POJ2060-Taxi Cab Scheme (最小路径覆盖)
- POJ 2060 Taxi Cab Scheme(匈牙利—最小路径覆盖)
- POJ 2060 Taxi Cab Scheme (最小路径覆盖)
- poj 2060 Taxi Cab Scheme (最小路径覆盖)
- poj2060——Taxi Cab Scheme(最小路径覆盖)