最小匹配hdu 3991 Harry Potter and the Present

本文介绍了一个基于图论的送货问题,通过求解任意两点间的最短路径并利用二分图匹配算法来找到最少的送货员数量,确保所有送货需求得到满足。

 

题目大意就是,有一个图,上面有一些顶点,代表一些城市,在某些时刻, 某个城市里会有人需要礼物, 哈利波特需要及时的将礼物送到,但是哈利每1秒只能走一个单位长度,所以他需要朋友的帮助,来使所有的人都能及时的收到礼物。问需要的最少的朋友个数。

那么看完题目后,实际上可以发现其跟路径覆盖非常有关系,因为是一些人走一些路径来将礼物送到。

所以要先将任意两点间的最短路求好。然后枚举任意两个任务,如果两点间的距离小于两点间的时间差,当然,这个时间差是有先后顺序的,这两个任务就可以进行连边,就这样,到最后可以发现是经典的最小路径覆盖模型。

要求最少需要多少个朋友帮他送礼物,每个城市在一个时间有人需要礼物,如果两个城市之间的距离小于两个城市中两个需要礼物的时间差的话,这两个礼物一个人送就可以了。就是用最少的人到达所有需要礼物的点,就是二分图的最小路径覆盖问题,之前我们要求出任意两点之间的最短距离,floyd求最短路。

 

 #include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define inf 99999999
int map[1010][1010];//只是求最短距离,不在find中
int link[1010],mark[1010];
int ma[1010][1010];//主要变量在find中
int m,n;
struct point 
{
    int x;
    int t;
}p[1000];
int cmp(const void *a,const void *b)//快排,是为了让一个人给你更多送礼物。。
{
    struct point *c=(struct point*)a;
    struct point *d=(struct point*)b;
    if(c->t!=d->t)
        return c->t-d->t;
    return c->x-d->x;
}
int find(int k)
{
    int i;
    for(i=0;i<n;i++)
    {
        if(mark[i]==-1&&ma[k][i])、、当m从零开始时,link和mark都要初始化为-1,(不然易岀错),当m从一开始时初始化为-1 和0均可以。。

        {
            mark[i]=1;
            if(link[i]==-1||find(link[i]))
            {
                link[i]=k;
                return 1;
            }
        }
    }
    return 0;
}
void flory()//最短距离的算法。。
{
    int i,j,k;
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            for(k=0;k<n;k++)
            {
                if(map[j][i]+map[i][k]<map[j][k])
                    map[j][k]=map[j][i]+map[i][k];
            }
}
int main()
{
    int i,j,k,Q,a,b,c,sum,r=0;
    scanf("%d",&k);
    while(k--)
    {
        r++;
        memset(ma,0,sizeof(ma));
        memset(link,-1,sizeof(link));
        scanf("%d%d%d",&n,&m,&Q);
        for(i=0;i<n;i++)//先初始化无穷大。。再利用flory
        {
          for(j=0;j<n;j++)
            map[i][j]=inf;
                map[i][i]=0;
        }
        for(i=0;i<m;i++)
            {
                scanf("%d%d%d",&a,&b,&c);
                if(map[a][b]>c)//两点之间了距离一样,双向。
                {
                    map[a][b]=c;
                    map[b][a]=c;
                }
            }
            flory();
            for(i=0;i<Q;i++)
                scanf("%d%d",&p[i].x,&p[i].t);
            qsort(p,Q,sizeof(p[0]),cmp);
            for(i=0;i<Q;i++)
                for(j=i+1;j<Q;j++)
                {
                    if(map[p[i].x][p[j].x]<=p[j].t-p[i].t)//满足条件ma置为一;
                        ma[i][j]=1;
                }
                sum=0;
                for(i=0;i<Q;i++)
                {
                        memset(mark,-1,sizeof(mark));
                        if(find(i))
                            sum++;
                }
                printf("Case %d: %d\n",r,Q-sum-1);
                }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值