您的位置:首页 > 其它

POJ2060 Taxi Cab Scheme [最小路径覆盖]

2011-08-18 14:16 363 查看
转载的文章:

根据这道题目的意思,我们可以建一张图,对于两个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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: