算法设计与分析——第五章回溯法 批处理作业调度 + 最大团问题+图的m着色问题

6、批处理作业调度(排列树)

每一个作业Ji都有两项任务分别在2台机器上完成。每个作业必须先有机器1处理,然后再由机器2处理。作业Ji需要机器j的处理时间为tji。对于一个确定的作业调度,设Fji是作业i在机器j上完成处理时间。则所有作业在机器2上完成处理时间和f=F2i,称为该作业调度的完成时间和。
在这里插入图片描述
在这里插入图片描述
也就是f1[i]=上一步的使用时间+自己消耗的时间,f2[i]=max(当前在机器1上的时间,上一步的使用时间)+自己消耗的时间。
详细的解释见参考文章

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int x[100];//当前的作业调度顺序
int bestx[100];//最优的调度顺序
int m[100][100];//各作业所需的处理时间
int f1,f2=0;//机器1、2完成时间
int bestf=1000;//最短完成时间
int cf=0,n;//当前完成时间和
Swap(int &a,int &b)
{
    int t=a;
    a=b;
    b=t;
}
void BackTrace(int t)
{
    if(t>n)
    {
        if(cf<bestf)
        {
            for(int i=1; i<=n; i++)
                bestx[i]=x[i];
            bestf=cf;
        }
    }
    else
    {
        for(int i=t; i<=n; i++)
        {
            f1+=m[x[i]][1];
            int tempf=f2;//保存的是上一个作业在f2的时间
            f2=(f1>f2?f1:f2)+m[x[i]][2];
            cf+=f2;
            if(cf<bestf)//超过最优时间就没必要继续了
            {
                Swap(x[t],x[i]);//回到上一个位置
                BackTrace(t+1);//再继续向下找
                Swap(x[t],x[i]);//得到一个最优后就要回溯
            }
            f1-=m[x[i]][1];
            cf-=f2;
            f2=tempf;
        }
    }
}
int main()
{
    int i,j;

    cout<<"请输入作业数:"<<endl;
    cin>>n;

    cout<<"请输入在各机器上的处理时间"<<endl;
    for(i=1; i<=2; i++) //i从1开始
        for(j=1; j<=n; j++)
            cin>>m[j][i];//第j个作业,第i台机器的时间值
    for(i=1; i<=n; i++)
        x[i]=i;//初始化当前作业调度的一种排列顺序
    BackTrace(1);

    cout<<"调度作业顺序:"<<endl;
    for(i=1; i<=n; i++)
        cout<<bestx[i]<<' ';
    cout<<endl;

    cout<<"处理时间:"<<endl;
    cout<<bestf;
    return 0;
}
/*
输入:
3
2 3 2
1 1 3
输出:
调度作业顺序:
1 3 2
处理时间:
18
*/

7、最大团问题

先看视频
理解后再看文章链接
总结: i从1开始向下找,如果i与当前所有解中有一个没有边,那么i不能放入解中,x[i]=0;否则cn++且x[i]=1。由于是深度优先搜索,所以先判断是否能进入左子树,能则(即x[i]=1)cn++,递归下一层且回退时cn–,不能则用限界函数判断是否需要进入右子树,cn+n-i>bestn时表示不选择当前的结点也可能获得更好的bestn,所以可以进入右子树。

#include <iostream>
using namespace std;
int m[100][100];//有向图的邻接矩阵
int x[100],bestx[100];//当前团的解 最优解
int n;//表示图的顶点数
int cn=0,bestn;//当前团的大小 当前最优值
void getbestn(int i)
{
    if(i>n) //递归出口,到根节点时,更新最优值和最优解,返回
    {
        bestn=cn;//更新最优值
        for(int j=1; j<=n; j++)
            bestx[j]=x[j];
        return ;//返回
    }
    x[i]=1;//先假定x[i]=1;
    for(int j=1; j<i; j++)
    {
        if(x[j]==1&&m[i][j]==0)//如果该点与已知解中的点无边相邻
        {
            x[i]=0;
            break;//则不遍历左子树
        }
    }
    if(x[i]==1) //当且仅当x[i]==1时,遍历左子树
    {
        cn++;//该点加入当前解
        getbestn(i+1);//递归调用
        cn--;//还原当前解
    }
    if(cn+n-i>bestn) 
    //如果当前值+右子树可能选择的节点>当前最优解则可以遍历右子树,否则无需继续进行
    {
        x[i]=0;
        getbestn(i+1);
    }
    return ;
}
int main()
{
    cin>>n;//输入图的顶点数
    //输入图的邻接矩阵
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            cin>>m[i][j];
    //求最优解
    getbestn(1);
    cout<<bestn<<endl;//输出最优值
    //输出
    for(int i=1; i<=n; i++)
        if(bestx[i])
            cout<<i<<" ";//输出最优解
    return 0;
}
/*
输入:
5
0 1 0 1 1
1 0 1 0 1
0 1 0 0 1
1 0 0 0 1
1 1 1 1 0
输出:
3
1 2 5
*/

8、图的m着色问题

先看视频链接
再看文章链接
总结: i从第一个节点开始,其颜色j从1到m种颜色中找,如果找到一个不会和相连结点重复的颜色,则color[j]++(第j种颜色被用过),同时递归下一层,没找到时回退同时color[j]–、i的颜色归0。到达叶节点时更新bestn、bestx[]。
代码:

#include<iostream>
using namespace std;
int c[100][100]; //邻接矩阵
int x[100],bestx[100];  //当前顶点i的颜色 最终节点i的颜色
int cn,bestn,m,n; //cn记录方案数 n个顶点 m种颜色
int color[100]; //color[i]!=0表示第i号颜色被用到过
int Check(int k)    //检查第k个顶点的颜色是否满足条件
{
    for(int i=1; i<=k; i++)
    {
        if(c[k][i]==1&&x[i]==x[k]) //k与i之间相连并且i顶点的颜色与k顶点的颜色相同
            return 0;
    }
    return 1;
}

void GraphColor(int i)
{
    if(i>n)  //到达叶结点
    {
        cn=0;
        for(int j=1; j<=m; j++)
        {
            if(color[j]) cn++;
        }
        if(bestn>cn||bestn==0)//出现更小的bestn
        {
            //更新最大颜色数
            bestn=cn;
            for(int j=1; j<=n; j++)
                bestx[j]=x[j];
        }
    }
    else
    {
        for(int j=1; j<=m; j++)
        {
            x[i]=j;   //首先将这个顶点颜色换为i
            if(Check(i)==1)  //检查是否符合条件
            {
                color[j]++;//满足则颜色数++
                GraphColor(i+1); //走下一步
                color[j]--;
            }
            x[i]=0;  //回溯 置为0
        }
    }
}

int main()
{
    int a,b;
    cin>>n>>m;
    //邻接表
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            cin>>c[i][j];
    //从第一个节点开始
    GraphColor(1);
    //输出各点的颜色
    for(int j=1; j<=n; j++)
        cout<<bestx[j]<<' ';
    cout<<endl;
    //总颜色数
    cout<<bestn;
    return 0;
}
/*
输入
5 4
0 1 1 1 0
1 0 1 1 1
1 1 0 1 0
1 1 1 0 1
0 1 0 1 0

输出
4 3 2 1 4
4
*/
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值