算法精解----8、集合应用-集合覆盖问题

1、问题具象:
有选手集合P={A1,A2,…}。每个选手有一个或多个技能。所有技能集合S={a,b,c,d,e,f,…..}。要求:选出最佳选手集合,包含所有技能,人员集合C。

2、解决方案:集合覆盖法(贪心法思路,不一定是最优解)
(1)选出有最多技能的人员Amax
(2)S中去掉Amax中的技能;P中去掉Amax
(3)循环找出下一个相对Amax,直到S中技能为0。

3、数据结构

#ifndef _COVER_H
#define _COVER_H
#include "set.h"

//每个人是一个节点 data指向KSet
typedef struct _ListElmt
{
    void *data;:

    struct _ListElmt *next;
}ListElmt;
//ListElmt:每个节点对应一个人,也用来set中的每个技能,data指向KSet

//KSet:key对应一个人的标记,set指向每个人的技能集合

typedef struct _KSet
{
    void *key;
    Set *set;
}KSet;

#endif

4、实现

#include <stdio.h>
#include "single_list.h"
#include "cover.h"

//skills是技能集合S, people是选手集合 P, repeople返回的 包含所有技能,人员集合C
int cover(Set *skills, Set *people, Set *repeople)
{
    Set intersection;//存两人技能的交集 
    KSet *pset;
    ListElmt *member, *max_member;//max_member存技能最多的人 
    void *data;
    int max_size;//存技能最多的人 的技能数 

    set_init(repeople, 0, people->match, NULL);

    while((set_size(skills) > 0) && (set_size(people) >0))
    {
        max_size=0;

        //找到现存人员中,技能最多的人 
        for(member = list_head(people);member != NULL;member=list_next(member))
        {
            if(set_intersection(&intersection, (KSet *)list_data(member)->set, skills)!=0)
                return -1;

            if(set_size(&intersection) > max)
            {
                max_member = member;
                max_size = set_size(&intersection);
            }

        }
        //把找到的人暂存入pset,再存入集合repeople
        pset = (KSet *)list_data(max_member); 
        set_insert(repeople, pset);

        //移掉已入组的人员 
        set_remove(people, (void **)&pset);
        //技能集合中去掉已经拿掉的人的技能 
        for(member = list_head( &((KSet *)list_data(max_member))->set);member != NULL;member=list_next(member))
        {
            data = list_data(member);
            set_remove(skills, (void **)&data);
        }
        //set_remove已经减了不需要sset->size = sset->size - max_size;
        //pset->size--;
        return 0;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值