UVAlive 3126(最小路径覆盖)

传送门
题解:
构造一个DAG,每个客人是一个节点,如果同一个出租车在接完客人u以后还来得及接客人v,那么连有向边(u,v)。

关于求DAG最小路径覆盖
以下内容转自XWL的博客
这里写图片描述
我们可以发现: 在DAG中,每条路径除了结尾的点,其他每个点都有一个唯一的后继结点。
举个例子:上图中 2->3->4 这条路径上,2的后继3、3的后继是4、4没有后继。
那么求路径条数的问题可以转换为求结尾结点的个数。
1.我们把DAG中的每个点 u 拆分成两个点u和u’把 u放入二分图的X集合,u’放入Y集合。
2.如果u->v有一条边,那么在二分图中连接u->v’
上面左图 ,按照以上两个步骤 ,可以建出右图。
因为每个点只属于一条路径,我们可以想到二分图匹配。
因为DAG中每个点的后继结点 就是 它在二分图上的匹配点
所以二分图最大匹配数=DAG中有后继结点的点的个数
我们要求 结尾结点(没有后继结点的点)的个数, 那么
最小路径数=结尾结点数=n-非结尾结点数=n-最大匹配数。 所以,
最小路径覆盖数=结点数-最大匹配数

看来匈牙利算法模板还挺稳当,居然1A了,耶~~ヾ(=^▽^=)ノ

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=502;
struct Point {
    int x,y;
};
struct Client {
    int tim;
    Point s,t;
    char ss[10];
    inline void read() {
        scanf("%s%d%d%d%d",ss,&s.x,&s.y,&t.x,&t.y);  
        tim=((ss[0]-'0')*10+ss[1]-'0')*60+(ss[3]-'0')*10+ss[4]-'0'; 
    }
}p[MAXN];
int n,link[MAXN];
bool cov[MAXN],mp[MAXN][MAXN];
inline int abs(int a) {return a>0?a:-a;}
inline int dis(Point a,Point b) {
    return abs(a.x-b.x)+abs(a.y-b.y);
}
inline bool check(Client a,Client b) {
    int t1=a.tim+dis(a.s,a.t)+dis(a.t,b.s);
    int t2=b.tim;
    return t1<t2;
}
bool dfs(int p) {
    for (int i=1;i<=n;++i) {
        if (mp[p][i]&&!cov[i]) {
            cov[i]=true;
            if (link[i]==-1||dfs(link[i])) {
                link[i]=p;
                return true;
            }
        }
    }
    return false;
}
int main() {
//  freopen("UVAlive 3126.in","r",stdin);
    int kase;
    scanf("%d",&kase);
    while (kase--) {
        memset(mp,false,sizeof(mp));
        memset(link,-1,sizeof(link));
        scanf("%d",&n);
        for (int i=1;i<=n;++i) p[i].read();
        for (int i=1;i<=n;++i)
            for (int j=1;j<=n;++j)
                mp[i][j]=check(p[i],p[j]);
        int mat=0;
        for (int i=1;i<=n;++i) {
            memset(cov,false,sizeof(cov));
            if (dfs(i)) ++mat;
        }
        printf("%d\n",n-mat);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值