8、集合应用-集合覆盖问题

来源:互联网 发布:windows聚焦图片 编辑:程序博客网 时间:2024/05/20 05:45

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指向KSettypedef 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返回的 包含所有技能,人员集合Cint 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;    }}