拟阵

目录

一,拟阵

1,拟阵

2,拟阵性质

3,独立子集的扩张

4,常见拟阵

5,图的拟阵

6,互补拟阵

二,加权拟阵

1,加权拟阵

2,最优子集

3,贪心问题的拟阵模型

4,求最优子集的通用算法

三,应用实例

单个处理器上对若干个单位时间任务的最优调度问题


一,拟阵

1,拟阵

换句话说,拟阵是一种满足遗传性和交换性的子集族。

2,拟阵性质

对于第二条,可以这么理解:

如果我们把I中不是I中其他任何元素的子集的元素,称为最大独立子集,那么最大独立子集的数量至少为1,而这些最大独立子集可以完全定义出I

因为任意一个最大独立子集的所有子集都是I的元素,而且这些子集就包含了I的所有元素。

对于第三条,其实就是给这些最大独立子集加以限定。

首先,所有最大独立子集的元素个数都是一样的

其次,如果构造一个图,每个节点对应一个最大独立子集,2个最大独立子集如果只有一个元素不同那么就连接一条边,那么这个图是无向连通图

最后,这个无向连通图是否还具有其他性质?比如含有哈密顿链路或环路?这个不太确定。

3,独立子集的扩张

如果x\notin A,\,A\cup{x}\in I,那么称x为A的扩张

4,常见拟阵

(1)S={1,2,3,4},I有9个元素{1,2}{1,3}{2,4}{3,4}{1}{2}{3}{4}{},其中{1,2}{1,3}{2,4}{3,4}是4个最大独立子集。

那么M=(S,I)就是一个简单的拟阵。

(2)S={1,2,3,4},I有11个元素{1,2}{1,3}{1,4}{2,3}{2,4}{3,4}{1}{2}{3}{4}{},其中{1,2}{1,3}{1,4}{2,3}{2,4}{3,4}是6个最大独立子集。

那么M=(S,I)就是一个简单的拟阵。

(3)显然(2)中的拟阵是非常简单的一种拟阵,可以直接推广:

(4)矩阵拟阵

(5)不那么显然的,(1)中的拟阵可以推广成:

5,图的拟阵

即S是一个图,它的所有无环边集构成一个拟阵。

根据图的性质很容易证明,这确实是拟阵,证明略。

对于一个全连通的图,最大独立子集就是生成树,元素个数就是 顶点数-1

6,互补拟阵

二,加权拟阵

1,加权拟阵

S中的每个元素都有一个权值,一个独立子集的权是它的所有元素的权之和

例如,图的拟阵中,权是边的长度,独立子集的权是所有包含的边的长度之和。

这里就得到了它和最小生成树的关系:对于一个全连通的图,如果每条边的权都大于0,那么权最小的最大独立子集就是最小生成树

2,最优子集

给定一个加权拟阵,所有元素的权都是正数,我们把具有最大权值的独立子集,称为最优子集。

因为所有元素的权值都是正数,所以最优子集一定是最大独立子集。

3,贪心问题的拟阵模型

很多贪心问题都可以转化成一个拟阵模型,即求最优子集。

例如求最小生成树,假设所以的边的权值都在(0,c)范围内,我们把所有边的权值乘以-1,再加上c,即从x变成c-x,

那么求最小生成树的问题,就转化成了求最大权值的最大独立子集,即求最优子集。

4,求最优子集的通用算法

算法非常简单,把所有元素按照权值递减排序,然后从头到尾扫描一遍,

独立子集A初始化为空集,扫描的过程中,如果A加上当前元素还是独立子集,那就加上,如果不是那就不加,

扫描完之后,就得到了最优子集。

实现:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

typedef struct Node //需要根据实际修改
{
    int w;
}Node;

#define N 100 //需要根据实际修改数值
Node s[N];

bool cmp(Node &a,Node &b)
{
    return a.w>b.w;
}

template<typename T>
bool check(vector<T>&A)//判断是否是独立子集
{
    return true; //需要根据实际修改逻辑
}

vector<Node> greedy()//求最优子集
{
    vector<Node>A;
    sort(s,s+N,cmp);
    for(int i=0;i<N;i++){
        A.push_back(s[i]);
        if(!check(A))A.pop_back();
    }
    return A;
}

int main()
{
    return 0;
}

其中,需要根据实际进行修改的有三处:规模N、结构体Node、判断是否是独立子集的函数check

时间复杂度:O(nlogn+nf(n)),其中f(n)是check函数运行的时间。

三,应用实例

单个处理器上对若干个单位时间任务的最优调度问题

思路:

首先,一个调度可以表示成早任务都在迟任务的前面的形式,早任务指的是能及时完成的任务。

其次,在早任务都在迟任务的前提下,一个调度可以表示成早任务全都是按照期限递增的形式。

所以,一个调度等价于一个早任务的集合。

那么,如何判断一个集合是不是独立集合呢?即如何实现check函数?

根据(2)即可完成check函数,时间复杂度为O(n)

所以整个算法的时间复杂度为O(n^2)

思路二:

如果不用拟阵,按照常规的贪心思路,把任务按照权值递减排序,然后从头到尾扫描,依次决定每个任务放到哪个位置,

如果当前还有时间槽可以完成这个任务,那就用其中最近(时间最靠后)的时间槽来完成这个任务,如果没有,那这个任务就是迟任务,不用调度了。

这个选时间槽的操作可以用并查集来完成:如还剩2个槽3,7,那么就有3棵树,根分别为0,3,7,成员分别是{0,1,2}{3,4,5,6}{7...},

这样就能根据任务的期限快速找出最近时间槽了。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值