zoukankan      html  css  js  c++  java
  • 回溯法实现n份作业分配给n个人完成的问题

    问题描述:

    有n份作业分配给n个人去完成,每人完成一份作业。假定第i个人完成第j份作业需要花费cij时间, cij>0,1≦i,j≦n。试设计一个回溯算法,将n份作业分配给n个人完成,使得总花费时间最短。

    问题思路:

    n分作业分配给n个人,共有A!中排列方式,深度优先遍历其排列数,如果遍历的路径已经比当前最小的话费则舍弃对当前路径的遍历,返回上层节点,寻找合适的路径,即回溯,如果最后可行解比当前的最小话费小,那么就更行最佳的作业安排顺序,同时更新最小的耗费时间。

    算法描述:

    t :递归的层数

    curr :当前的实际时间花费

    bestw :当前的最优的时间消耗

    arrange:任务的安排

    Backtrack(t)

      if t>=n 

        then if curr<bestw

          then bestw <- curr  

            update arrange

          ouput(arrange)

      else do

        for t to n do

          swap the arrange of t and i

          compute the current cost of the arrange

          if curr<bestw then backtrackt+1   

          swap the arrange of t and i

          give back the arrange t 

     数据结构的选择:使用数组是想对任务工作的安排

    算法的复杂度分析:On!)

    算法的实现:

    //backtrack.h
    #include <stdio.h>
    #include <stdlib.h>
    #include <limits.h>
    
    void backtrack(int t);//t为排列树的深度
    void getRslt(char filename[]);//从文件中读取数据,求解结果
    void output(int *arrange);//输入最终的任务分配结构
    void swap(int &a,int &b);//交换数组中的两个元素
    
    //backtrack.cpp
    
    #include "backtrack.h"
    #include <malloc.h>
    
    int *arrange;// 最终的作业分配安排
    int dataSize;//任务的个数 和人员的个数相同
    int **cost;//邻接矩阵用于存储每个人完成每份作业所需要的时间消耗
    int bestw=INT_MAX;//初始为最大的整数 若出现小的则更行
    int curr=0;
    int *best_arrange;
    
    void getRslt(char filename[])
    {
        FILE *fp;
        int i=0;
        int j=0;
    //    curr=0;
    
        fp=fopen(filename,"r");
        if (!fp)
        {
            printf("error,can not open the file%s",filename);
            return;
        }
    
        fscanf(fp,"%d",&dataSize);
        //开辟数据的空间,并将数据存在空间中
        best_arrange=(int*)malloc(dataSize*sizeof(int));
        cost=(int**)malloc(dataSize*sizeof(int*));
        for (i=0;i<dataSize;i++)
        {
            cost[i]=(int*)malloc(dataSize*sizeof(int));
            if (!cost[i])
            {
                printf("error can not malloc the space!");
            }
        }
        for (i=0;i<dataSize;i++)
        {
            for (j=0;j<dataSize;j++)
            {
                fscanf(fp,"%d",&cost[i][j]);
            }
        }
        arrange=(int *)malloc(dataSize*sizeof(int));
        if (!arrange)
        {
            printf("error,can not malloc a new space!");
        }
        for (i=0;i<dataSize;i++)
        {
            arrange[i]=i;
        }
    
        backtrack(0);
    
        output(best_arrange);
        printf("the best time is:%d\n",bestw);
        //释放开辟的空间避免内存泄露
        free(arrange);
        arrange=NULL;
        dataSize=0;
        for (i=0;i<dataSize;i++)
        {
            free(*(cost+i));
        }
    
        free(cost);
    
        cost=NULL;
        bestw=INT_MAX;
        curr=0;
        free(best_arrange);
        best_arrange=NULL;
    }
    void backtrack(int t)//t表示第t个作业cost[i][j]第i个人完成第j个任务所要完成的时间
    {
        int i=0;
        int j=0;
        if (t>=dataSize)//已经达到叶子节点 递归出口
        {
            if (curr<bestw)
            {
                bestw=curr;
                for (j=0;j<dataSize;j++)
                {
                    best_arrange[j]=arrange[j];
                }
            }
            return;
        }
    
        else
            for (i=t;i<dataSize;i++)//选取要递归的节点,依次递归节点的每一个孩子
            {
                swap(arrange[t],arrange[i]);//把第t个任务安排给arrang[i] 把第i个任务地第arrange[t]
                curr=curr+cost[arrange[t]][t];//当前时间家让把第t个任务我交给第arrange[i]所花费的时间
                if(curr>bestw)//当前的时间消耗已经超过当前的最佳时间 此时不用再递归其子节点 可以直接返回
                {    
                    curr=curr-cost[arrange[t]][t];
                    swap(arrange[t],arrange[i]);
                    continue;//本次循环结束
                }
    
                backtrack(t+1);//递归一直到叶节点
                curr=curr-cost[arrange[t]][t];//如果没有解则回溯
                swap(arrange[t],arrange[i]);
            }
    }
    
    void output(int *arrange)//打印最终的结果
    {
        int i=0;
        printf("the arrange of the work is:\n");
        for (i=0;i<dataSize;i++)
        {
            printf("the task %d is arranged to %d\n",(i+1),arrange[i]+1);
        }
    
    }
    
    void swap(int &a,int &b)//交换两个数的数值
    {
        int temp;
        temp=a;
        a=b;
        b=temp;
    }
    
    //main.cpp
    
    #include "backtrack.h"
    #include <string.h>
    
    int main()
    {
        char filename[256]="ddddd";
        while (1)
        {
            printf("please input the name of data file(input ‘exit’to quit the program):\n");
            gets(filename);
            if (!strcmp(filename,"exit"))
            {
                break;
            }
            getRslt(filename);
        }
        return 1;
    }
  • 相关阅读:
    如何理解volatile关键字
    Spring 4+JMS+ActiveMQ Example with Annotations
    Spring MVC如何获得客户端IP地址
    PDFBox –如何读取PDF的内容
    Spring MVC 使用Ehcache作为缓存的例子
    自定义了一个data table控件
    Linux基本配置
    位操作学习
    QT——QPainter类详解
    QT——设计文件的和控制类的关联问题
  • 原文地址:https://www.cnblogs.com/liwenzhu/p/3504287.html
Copyright © 2011-2022 走看看