LA 3126 二分匹配---DAG中的最小路径应用

来源:互联网 发布:java形参改变实参 编辑:程序博客网 时间:2024/06/16 18:24

题意:有 n 个顾客 , 需要坐出租车从一个地方去另一个地方 , 每个顾客的出发时间、出发地点、目的地点都已给出 , 从出发地点到目的地点的时间为两地之间的路径长度 , 并且出租车要比顾客的出发时间早一分钟到达 , 问最少需要派出多少辆出租车。


解法:我们先这样来构图 , 每个顾客是一个结点,如果同一个出租车在接完客人 u 之后还来得及节客人 v , 那么就在 u 到 v 之间连一条有向边 。 由此可以发现 , 这个图是一个DAG , 那么我们就只需要找最小路径覆盖(最小路径覆盖:是指在图中找尽量少的路径,去覆盖每一个点,并且每个路径之间没有公共点)。


对于最小路径覆盖,我们先进行拆点  , 把图边为一个二分图 , 把所有结点 拆为两个结点 , 如 结点 u 拆为 u1 , u2 , 如果 u 到 v 有一条有向边 , 那么我们就连接 u1 到 v2 的一条边。

这时我们只需要求出这个图的最大匹配 , 结果就是: n - m(最大匹配数)。


为什么?

因为匹配和路径覆盖是一一对应的 , 对于路径覆盖中的每条简单路径 , 除了最后一个“结尾结点”之外,都有唯一的后继与其对应(也就是匹配结点) , 因此匹配数就是非“结尾结点”的个数 , 但匹配数达到最大时 , 也就是“结尾结点”最小 , 也就是路径最小。


代码:

#include <iostream>#include <stdio.h>#include <string.h>#include <vector>#include <cmath>using namespace std;#define maxn 520vector<int>grap[maxn];int cab[maxn][4] , cab_t[maxn][2];int n;int pre[maxn] , cx[maxn] , cy[maxn];void init(){    for(int i = 0; i < n; i++)        grap[i].clear();    memset(cx , -1 , sizeof(cx));    memset(cy , -1 , sizeof(cy));}void create_grap(){    int i , j;    int x , y;    int h , m;    for(i = 0; i < n; i++)    {        y = abs(cab[i][0]-cab[i][2])+abs(cab[i][1]-cab[i][3]);        for(j = 0; j < n; j++)        {            if(i == j)  continue;            x = y+abs(cab[j][0]-cab[i][2])+abs(cab[j][1]-cab[i][3]);            m = (x+cab_t[i][1])%60;            h = cab_t[i][0]+(x+cab_t[i][1])/60;            if(h < cab_t[j][0] || (h == cab_t[j][0]&&m < cab_t[j][1]))                grap[i].push_back(j);        }    }}int findpath(int u){    int i , v;    for(i = 0; i < grap[u].size(); i++)    {        v = grap[u][i];        if(!pre[v])        {            pre[v] = 1;            if(cy[v] == -1 || findpath(cy[v]))            {                cy[v] = u;                cx[u] = v;                return 1;            }        }    }    return 0;}int match(){    int i , cas = 0;    for(i = 0; i < n; i++)        if(cx[i] == -1)        {            memset(pre , 0 , sizeof(pre));            cas += findpath(i);        }    return cas;}int main(){    int t;    scanf("%d" , &t);    while(t--)    {        scanf("%d" , &n);        init();        int i ;        for(i = 0; i < n; i++)            scanf("%d:%d %d %d %d %d" , &cab_t[i][0] , &cab_t[i][1] , &cab[i][0] , &cab[i][1] , &cab[i][2] , &cab[i][3]);        create_grap();        int cas = match();        cout<<n-cas<<endl;    }    return 0;}


0 0
原创粉丝点击