Hdu 1350 Taxi Cab Scheme【最小边覆盖】

二分图:
最小顶点覆盖=最大匹配
最小边覆盖=顶点数-最小顶点覆盖(最大匹配)
最小边覆盖:实质是个边集,这个集合里的边能覆盖所有的点,最小边覆盖是满足这个要求的所有边集中边数最少的一个。

这里顶点数等于总的顶点数,是二分图两边的顶点数,不是一边。

证明:设最大匹配数为m,总顶点数为n。为了使边数最少,又因为一条边最多能干掉两个点,所以尽量用边干掉两个点。也就是取有匹配的那些边,当然这些边是越多越好,那就是最大匹配了,所以先用最大匹配数目的边干掉大多数点。剩下的解决没有被匹配的点,就只能一条边干掉一个点了,设这些数目为a,显然,2m+a=n,而最小边覆盖=m+a,所以最小边覆盖=(2m+a)-m=n-m。
 

这是模板题,直接上代码

///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const ll mod=998424353;
const int INF=0x3f3f3f3f;
const int maxn=1e5+5;

struct node
{
    int t;
    int x1;
    int y1;
    int x2;
    int y2;
    int d;
}bus[505];

vector<int>load[505];

int vis[505];
int match[505];

bool dfs(int s)
{
    int d=load[s].size();
    for(int i=0;i<d;i++)
    {
        int e=load[s][i];
        if(!vis[e])
        {
            vis[e]=1;
            if(match[e]==-1||dfs(match[e]))
            {
                match[e]=s;
                return true;
            }
        }
    }
    return false;
}

int main()
{
    int T,n;
    scanf("%d",&T);
    int h,m;
    while(T--)
    {
        for(int i=0;i<=500;i++)
            load[i].clear();
        memset(match,-1,sizeof(match));
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d:%d",&h,&m);
            bus[i].t=m+h*60;
            scanf("%d %d %d %d",&bus[i].x1,&bus[i].y1,&bus[i].x2,&bus[i].y2);
            bus[i].d=abs(bus[i].x1-bus[i].x2)+abs(bus[i].y1-bus[i].y2);
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=i+1;j<=n;j++)
            {
                int dis=abs(bus[i].x2-bus[j].x1)+abs(bus[i].y2-bus[j].y1);
                if(bus[i].t+bus[i].d+dis<bus[j].t)
                    load[i].push_back(j);
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            memset(vis,0,sizeof(vis));
            if(dfs(i))
                ans++;
        }
        printf("%d\n",n-ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值