POJ3216 Repairing Company【二分图最小路径覆盖】【Floyd】

题目链接:

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

题目大意:

有Q个地点,告诉你Q个地点之间的相互距离(从i地点赶到j地点需要的时间)。有M项任务,

给你M项任务所在的地点block、开始时间start和任务完成需要时间time。一个工人只有在

他准备完成的下一项任务开始之前完成手上的任务,然后在下一项任务开始之前赶到下一项

任务的地点,才能完成这两项任务。问:最少需要多少个工人来完成这M项任务。

思路:

先用Floyd算出Q个地点之间相互最短距离。然后建立一个二分图,每边都是M项任务,如果

能在任务j完成之前将i任务完成并能赶到任务j的地点,就建立一条边。那么问题就变为了求

二分图最小路径覆盖问题。而二分图最小路径覆盖 = 点数 - 二分图最大匹配。二分图最大匹

配用匈牙利算法来求。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 25;
const int MAXM = 220;
const int INF = 0xffffff0;

int G[MAXN][MAXN],Dist[MAXN][MAXN];

struct Node
{
    int block;
    int start;
    int time;
}node[MAXM];

void Floyd(int N)
{
    for(int i = 1; i <= N; ++i)
        for(int j = 1; j <= N; ++j)
            Dist[i][j] = G[i][j];

    for(int k = 1; k <= N; ++k)
        for(int i = 1; i <= N; ++i)
            for(int j = 1; j <= N; ++j)
                if(Dist[i][k] + Dist[k][j] < Dist[i][j])    //加Dist[i][j] != INF && Dist[k][j] != INF出错。。。
                    Dist[i][j] = Dist[i][k] + Dist[k][j];

}

bool Map[MAXM][MAXM],Mask[MAXM];
int NX,NY;
int cx[MAXM],cy[MAXM];

int FindPath(int u)
{
    for(int i = 1; i <= NY; ++i)
    {
        if(Map[u][i] && !Mask[i])
        {
            Mask[i] = 1;
            if(cy[i] == -1 || FindPath(cy[i]))
            {
                cy[i] = u;
                cx[u] = i;
                return 1;
            }
        }
    }
    return 0;
}

int MaxMatch()
{
    for(int i = 1; i <= NX; ++i)
        cx[i] = -1;
    for(int i = 1; i <= NY; ++i)
        cy[i] = -1;

    int res = 0;
    for(int i = 1; i <= NX; ++i)
    {
        if(cx[i] == -1)
        {
            for(int j = 1; j <= NY; ++j)
                Mask[j] = 0;
            res += FindPath(i);
        }
    }
    return res;
}

int main()
{
    int Q,M;
    while(~scanf("%d%d",&Q,&M) && (Q||M))
    {
        for(int i = 1; i <= Q; ++i)
        {
            for(int j = 1; j <= Q; ++j)
            {
                scanf("%d",&G[i][j]);
                if(G[i][j] == -1)
                    G[i][j] = INF;
            }
        }
        for(int i = 1; i <= M; ++i)
            scanf("%d%d%d",&node[i].block,&node[i].start,&node[i].time);

        Floyd(Q);
        memset(Map,0,sizeof(Map));
        for(int i = 1; i <= M; ++i)
        {
            for(int j = 1; j <= M; ++j)
            {
                int u = node[i].block;
                int v = node[j].block;
                if(i != j && Dist[u][v] != INF)
                {
                    if(node[i].start + node[i].time + Dist[u][v] <= node[j].start)
                        Map[i][j] = 1;
                }
            }
        }
        NX = NY = M;
        printf("%d\n",M-MaxMatch());
    }

    return 0;
}
时间: 2024-10-10 20:22:48

POJ3216 Repairing Company【二分图最小路径覆盖】【Floyd】的相关文章

POJ - 3216 Repairing Company 二分图 最小路径覆盖

题目大意:有一个人开了一间维修店.某天,该维修店接收到了Q个任务,这Q个任务分布在M个城市中.每个任务有三个值,分别是所在城市,起始时间,维修时间. 现在给出M个城市的路线图,路线对应的是从某城市到某城市的所需时间. 问至少要派多少个维修人员才能完成这Q个任务 解题思路:现将能联通的城市联通起来,用floyd求出城市之间的时间数 接着就要找关系了,如果 起始时间 + 维修时间 + 两个城市来往的时间 <= 另外一个任务的起始时间 就表示该任务做完后可以接着做下一个任务,这样关系就明确了 现在要求

POJ 3216 Repairing Company(最小路径覆盖)

POJ 3216 Repairing Company 题目链接 题意:有m项任务,每项任务的起始时间,持续时间,和它所在的block已知,且往返每对相邻block之间的时间也知道,问最少需要多少个工人才能完成任务,即x最少是多少 思路:先floyd求出每两个block之间的最小距离,然后就是最小路径覆盖问题,一个任务之后能赶到另一个任务就建边 代码: #include <cstdio> #include <cstring> #include <algorithm> #i

POJ2594 Treasure Exploration【二分图最小路径覆盖】【Floyd】

题目链接: http://poj.org/problem?id=2594 题目大意: 给你N个地点,M条有向边,已知构成的图是有向无环图.现在要在地点上放机器人通过M 条边来遍历N个地点,问:最少需要多少个机器人可以遍历N个地点. 思路: 这是一道求最小路径覆盖的题目.和一般最小路径覆盖的题目不一样的地方是:这里的点可 以重复遍历.也就是可以有两个及以上的机器人经过同一个点. 那么,先建立一个二分图, 两边都为N个地点.然后在原图的基础上,用Floyd求一次传递闭包,也就是如果点i可以到达 点j

poj 3020 二分图最小路径覆盖

二分图最小路径覆盖=|v|-最大匹配.此题为有向图,切所有边正反向存了两遍,所以结果匹配数要除以2 // // main.cpp // poj3020 // // Created by Fangpin on 15/5/29. // Copyright (c) 2015年 FangPin. All rights reserved. // #include <iostream> #include <cstdio> #include <vector> #include <

POJ1422 Air Raid【二分图最小路径覆盖】

题目链接: http://poj.org/problem?id=1422 题目大意: 有N个地点和M条有向街道,现在要在点上放一些伞兵,伞兵可以沿着有向街道走,直到不能走为止. 每条边只能被一个伞兵走一次.问:至少放多少伞兵,能使伞兵可以走到图上所有的点. 思路: 很明显的最小路径覆盖问题.先转换为二分图,先将N个点每个点拆成两个点,左边是1~N个点,右 边也是1~N个点.将有向街道变为左边点指向右边点的边. 因为二分图最小路径覆盖 = 点数 - 二分图最大匹配数,则求出结果就是放的最少伞兵数.

HDU1151_Air Raid(二分图/最小路径覆盖=n-最大匹配)

解题报告 题目传送门 题意: 一个小镇,所有的街道都是单向的,这些街道都是从一个十字路口通往另一个十字路口,已知从任何十字路口出发,沿着这些街道行走,都不能回到同一个十字路口,也就是说不存在回路. 计算攻击这个小镇需要派的伞兵最少数目,这些伞兵要走遍小镇的所有十字路口,每个十字路口只由一个伞兵走到.每个伞兵在一个十字路口着陆,沿着街道可以走到其他十字路口. 思路: 用最小的伞兵覆盖街道,最小路径覆盖模型.把每个点拆成X1,Y1,这样建成二分图.最小路径覆盖=n-最大匹配数. #include <

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

Running a taxi station is not all that simple. Apart from the obvious demand for a centralised coordination of the cabs in order to pick up the customers calling to get a cab as soon as possible,there is also a need to schedule all the taxi rides whi

poj3216Repairing Company 二分匹配之最小路径覆盖+floyd

//m个任务,每个任务都有开始时间和需要花的时间,以及其在哪楼地方工作 //给出地图,每楼到另一楼的路径所花的时间 //问最少需要安排多少人能完成这些任务 //对任务和任务之间建图,如果做完任务i还能做任务j那么i-j之间建立一条边 //这样只需要找到最小路径覆盖即为最终答案 #include<cstdio> #include<iostream> #include<cstring> using namespace std ; const int maxn = 210 ;

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

题目大意:有n项任务,给出每项任务的出发时间,出发地点和目的地. 当一个任务完成之后,如果 当前时间 + 到达另一个任务的出发地的时间 <= 另一个任务的出发时间 - 1 的话,那么就可以让这个人接下去完成这个任务了 问至少需要派多少人才可以完成任务 解题思路:这题和 poj-3216 Repairing Company很像 两个点集都是任务,如果一个任务完成了可以接下来完成另一个任务的话,那么这两个任务之间就存在关系了,这样二分图就建成了 因为要把所有的任务都完成,也就是说要覆盖所有点,这就变