划分无冲突子集问题
来源:互联网 发布:mac开机进度条卡住 编辑:程序博客网 时间:2024/05/19 11:50
问题背景:某运动会设立N个比赛项目,每个运动员可以参加1-3个项目。试问如何安排比赛日程,既可以使同一运动员参加的项目不安排在同一单位时间进行,又使总的竞赛日程最短。
问题抽象:若将此问题抽象成数学模型,则归属于“划分子集”问题。N个比赛项目构成一个大小为n的集合,有同一运动员参加的项目则抽象为“冲突”关系。
解决问题:假设某运动会设有9个项目,A = {0, 1, 2, 3, 4, 5, 6, 7, 8},7名运动员报名参加的项目分别为:(1, 4, 8)、(1, 7)、(8, 3)、(1, 0, 5)、(3, 4)、(5, 6, 2)和(6, 4),则构成一个冲突关系的集合R = { (1, 4), (4, 8), (1, 8), (1, 7), (8, 3), (1, 0), (0, 5), (1, 5), (3, 4), (5, 6), (5, 2), (6, 2), (6, 4)}(一对括号中的两个项目不能安排在同一单位时间)。“划分子集”问题即将集合A划分成k个互不相交的子集A1, A2, ... , Ak(k <= n),使同一子集中的元素均无冲突关系。
解决方法:利用队列先进先出的特点,将待划分的集合A中的所有元素放入一个队列中,然后依次取出元素放入一个待分配的组中,若当前元素与改组中已经入选的元素无冲突,则出栈,如果产生冲突则继续放在队列的尾部;当遍历考察一轮队列中的所有元素后,产生一个无冲突的子集,如此循环直到所有元素都被分配完成时结束分配。
源文件:main.cpp(重点在于子函数DividSubset的实现) SqQueue.h SqQueue.cpp
main.cpp文件:
#include <iostream>#include "SqQueue.h"#define ITEM 9 //ITEM宏表示待处理集合中元素的项数using namespace std;int R[ITEM][ITEM] = { //该矩阵用来存储待划分集合中元素之间的冲突关系,0代表不冲突,1代表冲突{0, 1, 0, 0, 0, 1, 0, 0, 0},{1, 0, 0, 0, 1, 1, 0, 1, 1},{0, 0, 0, 0, 0, 1, 1, 0, 0},{0, 0, 0, 0, 1, 0, 0, 0, 1},{0, 1, 0, 1, 0, 0, 1, 0, 1},{1, 1, 1, 0, 0, 0, 1, 0, 0},{0, 0, 1, 0, 1, 1, 0, 0, 0},{0, 1, 0, 0, 0, 0, 0, 0, 0},{0, 1, 0, 1, 1, 0, 0, 0, 0}};int result[ITEM]; //该数组用来存放分组后的结果/*********************************************************** *功能:划分给定集合的无冲突子集 *输入:集合中元素关系集,集合中基本元素的个数,存储结果的数组 *时间:2016年10月17日 ***********************************************************/void DivideSubset(int R[][ITEM], int n, int result[]){ int PreIndex = n, GroupIndex = 0; //PreIndex表示前一次出队列的元素序号,GroupIndex表示当前分配的组的编号 SqQueue SQ; InitQueue(SQ); //初始化一个队列,长度与被划分集合的基本元素个数相同,本例中取9 for(int i = 0 ; i < n ; ++i) //该循环用来给分配的队列附上初值,该例中为(0-8) { EnQueue(SQ, i); } int currVal; //该变量用来表示当前待考察的队列中的一个元素 int clash[ITEM]; //该数组用来表示当前分配组的已经添加的元素与其它元素的关系,即是否产生冲突 while(!QueueEmpty(SQ)) //该循环用来处理队列中的每一个元素,知道所有元素都分配完成时结束 { DeQueue(SQ, currVal); //取出一个元素进行处理 if(currVal <= PreIndex) //如果当前元素小于前一个,则表示队列已经循环遍历所有的元素,应该新建另一个组 { ++GroupIndex; for(int i = 0 ; i < n ; ++i) clash[i] = 0; } if(clash[currVal] == 0) //查询当前分配组的clash数组的值,当值为0时表示该元素没有与当前组中已经添加的元素产生冲突 { result[currVal] = GroupIndex; //将当前元素编入该组 for(int i = 0 ; i < n ; ++i) //添加与被添加元素冲突的信息 clash[i] += R[currVal][i]; } else { EnQueue(SQ, currVal); //如果该元素与当前组中的所有元素都冲突,将该元素继续入栈 } PreIndex = currVal; }}int main(){ DivideSubset(R, ITEM, result); for(const auto &e : result) { cout << e << " "; } cout << endl; return 0;}
SqQueue.h文件:
#ifndef SQQUEUE_H#define SQQUEUE_H#define MAXQSIZE 10 //队列的最大长度typedef int QElemType;typedef struct{ QElemType *base; //初始化的动态分配存储空间 int front; //头指针,若队列不空,指向队列头元素 int rear; //尾指针,若队列不空,指向队列尾元素的下一个位置}SqQueue;bool InitQueue(SqQueue &Q); //按指定大小构造一个顺序空队列Qint QueueLength(SqQueue &Q); //返回Q的元素的个数,即队列长度bool EnQueue(SqQueue &Q, QElemType e); //插入元素e为Q的新的队尾元素bool DeQueue(SqQueue &Q, QElemType &e); //对头元素出队列void PrintSqQueue(SqQueue &Q); //打印顺序队列bool QueueEmpty(SqQueue &Q); //判断给定的队列是否为空队列#endif /* SqQueue.h */
SqQueue.cpp文件:
#include "SqQueue.h"#include <stdlib.h>#include <iostream>using namespace std;bool InitQueue(SqQueue &Q){ Q.base = (QElemType*)malloc(MAXQSIZE*sizeof(QElemType)); if(Q.base == nullptr) return false; Q.front = Q.rear = 0; return true;}int QueueLength(SqQueue &Q){ return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;}bool EnQueue(SqQueue &Q, QElemType e){ if(((Q.rear + 1) % MAXQSIZE) == Q.front) return false; Q.base[Q.rear] = e; Q.rear = (Q.rear + 1) % MAXQSIZE; return true;}bool DeQueue(SqQueue &Q, QElemType &e){ if(Q.rear == Q.front) return false; e = Q.base[Q.front]; Q.front = (Q.front + 1) % MAXQSIZE; return true;}void PrintSqQueue(SqQueue &Q){ int i = Q.front; while(i != Q.rear) { cout << Q.base[i] << " "; i = (i + 1) % MAXQSIZE; } cout << endl;}bool QueueEmpty(SqQueue &Q){ return (Q.front == Q.rear) ? true : false;}
在ubuntu14.04环境中,采用g++编译(g++ -std=c++11 main.cpp SqQueue.cpp),然后运行结果为集合A中的每个元素所分配组的编号:
结果:1组(0, 2, 3, 7)、2组(1, 6)、3组(4, 5)、4组(8)
参考文献:《数据结构及应用算法教程》/严蔚敏,陈文博编著.-修订本-.--北京:清华大学出版社,2011,5
- 划分无冲突子集问题
- 划分无冲突子集问题
- 划分无冲突子集问题
- 划分无冲突子集
- DP——划分子集和问题
- 【NPC】14、子集和问题规约到划分问题
- 数据结构_队列应用举例_划分子集问题
- 数据结构_队列应用举例_划分子集问题
- 子集问题
- 划分两个子集使其合相等
- 划分和相等的子集-LintCode
- 求子集问题
- 求集合子集问题
- 求子集问题
- 子集树变式问题
- 子集和问题
- 集合子集问题:
- 子集和问题
- 从chrome源码到xilium.CefGlue集成注意事项
- Java代码规范总结
- linux网络编程之TCP/IP基础(三):IP数据报格式和IP地址路由
- Clojure介绍、安装和语法
- linux网络编程之TCP/IP基础(四):TCP连接的建立和断开、滑动窗口
- 划分无冲突子集问题
- 【分享】10个帮你修图+剪辑视频+PPT制作的网站
- Android 自定义进度条
- linux网络编程之TCP/IP基础(五):分析一帧基于UDP的TFTP协议帧
- 模式九:模板方法模式(Template Pattern)——封装算法块
- Window进程管理
- MySQL InnoDB四个事务级别 与 脏读、不重复读、幻读
- 弹性盒子常用属性
- java中类与类之间的关系