求解约束化问题

求解约束化问题

题目描述:

如何节省工料的约束化问题,其中集合A是工料结合,集合B是部件集合,集合A和集合B中的数值代表工料和部件长度,问题就是用集合A里面的工料生产,集合B里面的部件,目标是节省工件。

给定两个集合A和B。集合的元素都是大于0的实数。假设A有m个元素,B有n个元素。将B的每个元素映射到A的某个元素,可以多对一映射。

输入和输出的格式

输入文件为input.txt,共4行,第一行为A的元素个数m,第2行为m个值,用英文逗号隔开,代表A的元素,第3行为B的元素个数n,第4行为n个值,用英文逗号隔开,代表B的元素。m和n的最大值200。

//输入文件
4
3.5,6,9.2,10
3
1,2,4.5

//输出文件
1,3,9.2
2,3,9.2
4.5,3,9.2 

输出文件为output.txt,共n行,每行3个值,其中第i行的第一个值是B里面第i个值,第二个值是一个索引值j,表示将B里面的第i个值映射到A的第j个值,第三个值是A里面的第j个值的具体数值。i和j的取值都是从1开始。每行的值用英文逗号隔开。

题目分析

本题的实质是建立两个数组之间的映射关系

A:[3.5,6,9.2,10]

B:[1,2,4.5]

找到A中满足B元素总和的最小要求,但同时还需要是的,这个最小要求,不能在一个物料满足不了的条件下,去用另一种物料

例如,3.5>1+2,并且余留下0.5的多余边角料,但不能把这个多余的分配给4.5,只能重新挑选满足其长度要求的单个值。

那么我便来理清一下我的思路:

  1. 读取文件的内容
  2. 将字符串的内容提取到数组中去,这样方便处理
  3. 建立值和下标的映射关系
  4. 计算数组存在的所有子集
  5. 计算所有子集的和
  6. 跟B所需的物料进行比较得出最小的物料消耗
  7. 寻找最优的A里的元素分配给B里的元素的分配方式
  8. 当A中的最优分配方式中,一种物料不能完全满足,需要外借,将这种剔除。重新寻找最优的分配方式,直到找到为止
  9. 将找到的最优分配方式保存在结构体容器中,然后输出即可。
代码实现
#include<iostream>
#include<map>
#include<string>
#include<vector>
#include<fstream>
#include<algorithm>

using namespace std;

//建立值和坐标的映射关系
//值
//对应的下标
struct MyPoint
{
    float val;
    int index;
};

//存储将要输出的结果
struct compearStrust
{
    float valB;
    int indexA;
    float valA;
};

//读取input中的文件值,并将该值转换称字符串处理
void readInput(string &strA,string &strB)
{
    ifstream fd;
    fd.open("input.txt",ios::in);
    if(!fd.is_open())
    {
        cout<<"文件打开失败"<<endl;
    }
    //设定读取的每一行的大小,即读取的缓冲区的大小为200字节
    char buff[200];
    int row=1;
//只读取输入文件中waaaaaaaaaaaaaaaaaaaaaaaa第2行和第4行的数据
    while(fd>>buff)
    {
        if(row==2)
        {
            strA=buff;
        }
        if(row==4)
        {
            strB=buff;
        }
        row++; 
    }
    fd.close();
}

//切割字符串,将字符串中的数字提取到vector容器中
void spiltStr(string str,const string &spilt,vector<string>&strList)
{
    //确保是个空的vector容器
    strList.clear();
    if(str=="")
    {
        return;
    }
    string strs=str+spilt;
    //获取查找分割符的第一个下标
    //find查找的到返回当前的下标,查找不到返回npos
    int pos=strs.find(spilt);
    int steps=spilt.size();
    //find执行查找下标的操作
    //substr执行复制和切割字符串的功能
    while(pos!=strs.npos)
    {
        string temp=strs.substr(0,pos);
        strList.push_back(temp);
        strs=strs.substr(pos+steps,strs.size());
        pos=strs.find(spilt);
    }

}

//定义排序的规则,根据结点的值进行排序,小的在前大的在后
bool sortRegular(MyPoint &list1,MyPoint&list2)
{
    return list1.val<list2.val;
}

//遍历listA中所有可能的集合
//使用迭代的方法来实现
//这个方法是参考leetcode第78题的内容
void getSubsets(vector<MyPoint>nums,vector<bool>tag,int depth,vector<vector<MyPoint>>&ans)
{
    if(depth==nums.size())
    {
        int sum=0;
        vector<MyPoint> temp;
        MyPoint mypoint;

        for(int i=0;i<tag.size();i++)
        {
            if(tag[i]==true)
            {
                mypoint.val=nums[i].val;
                mypoint.index=nums[i].index;
                temp.push_back(mypoint);
                sum=sum+nums[i].val;
            }

        }
        ans.push_back(temp);
    }
    else{
        tag[depth]=true;
        getSubsets(nums,tag,depth+1,ans);
        tag[depth]=false;
        getSubsets(nums,tag,depth+1,ans);
    }
}


//获取arr中所有排列的值的和
void getSumArray(vector<float>&sumArray,vector<vector<MyPoint>>ans)
{
    vector<MyPoint>temp;
    float sum=0;
    //end()-1去除空的数组
    for(auto it=ans.begin();it!=ans.end()-1;it++)
    {
        sum=0;
        temp=*it;
        for(auto it1:temp)
        {
           sum=sum+it1.val;
        }
        sumArray.push_back(sum);
    }
}


//寻找最符合B集合的值
//即满足刚好大于却又足够小的关系
void findCompareB(vector<float>sumArray,float sum ,float &bestSum,int &bestIndex)
{
    //index代表的是sum对应的坐标
    int index=0;
    bestSum=*max_element(sumArray.begin(),sumArray.end());
    bestIndex=0;
    for(auto i:sumArray)
    {
        if(i>=sum)               
        {
            if(i<bestSum)
            {
                bestSum=i;
                bestIndex=index;
            }
        }
        index++;
    }
}



//给listB分配最适合A的值
bool distributedArray(vector<vector<MyPoint>>&ans,vector<MyPoint>listB,int bestIndex,vector<compearStrust>&saveList ,int &indexB)
{   
    compearStrust saveStruct;
    indexB=0;
    int indexA=0;
    vector<MyPoint>tempList=listB;
    vector<vector<MyPoint>>tempListAns=ans;
    while(indexB<tempList.size())
    {
        
        if(indexA<tempListAns[bestIndex].size())
        {
            if(tempListAns[bestIndex][indexA].val>listB[indexB].val)
            {
                //更新原始的值
                tempListAns[bestIndex][indexA].val=tempListAns[bestIndex][indexA].val-listB[indexB].val;
                //把对应的结点的值传到结构体中
                saveStruct.valB=listB[indexB].val;
                saveStruct.valA=ans[bestIndex][indexA].val;
                saveStruct.indexA=ans[bestIndex][indexA].index;
                saveList.push_back(saveStruct);
                
                tempList[indexB].val=0;
                indexB++;
            }
            else{
                indexA++;
            }
        }
        //当超出了
        else{
            return false;
        }
    }
    return true;
}


//寻找最合适的sum
//避免一个物料被分后,不够分,需要从别人那里借用
void searchBestChiose(vector<vector<MyPoint>>&ans,vector<float>&sumArray,float sum,vector<compearStrust>&saveList,vector<MyPoint>listB)
{
    int indexB=0;
    float bestSum=*max_element(sumArray.begin(),sumArray.end());
    int bestIndex=0;
    while(indexB<listB.size())
    {
        findCompareB(sumArray,sum,bestSum,bestIndex);
        //如果物料分配不满足,则重置参数
        if(!distributedArray(ans,listB,bestIndex,saveList,indexB))
        {
            saveList.clear();
            indexB=0;
            ans.erase(ans.begin()+bestIndex);
            sumArray.erase(sumArray.begin()+bestIndex);
        }
    }
}

//将查找的结果写入到输出文件中
void printResult(vector<compearStrust>&saveList)
{
    ofstream ofs;
    //打开文件,打开文件用于写入数据,如果文件不存在,则新建该文件
    //若文件原本就存在,则打开时清除原来的内容
    ofs.open("output.txt",ios::out);
    int currIndex=0;
    //到最后第二个执行换行
    while(currIndex<saveList.size()-1)
    {
        ofs<<saveList[currIndex].valB<<","
        <<saveList[currIndex].indexA<<","
        <<saveList[currIndex].valA
        <<endl;
        currIndex++;
    }
    //到最后一个不用换行
     ofs<<saveList[currIndex].valB<<","
        <<saveList[currIndex].indexA<<","
        <<saveList[currIndex].valA;
    ofs.close();
}


int main()
{
    string strA;
    string strB;
    vector<string>strlistA;
    vector<string>strlistB;
    //读取输入的文件
    readInput(strA,strB);
    cout<<strA<<endl;
    cout<<strB<<endl;

    //对输入的文件的字符串进行切割,保存到vector容器中
    spiltStr(strA,",",strlistA);
    spiltStr(strB,",",strlistB);

    int lensA=strlistA.size();
    int lensB=strlistB.size();
    
    //对结构体进行实例化
    //listA 和 listB 保存的是对应的值和坐标
    MyPoint mypoint;
    vector<MyPoint>listA;
    vector<MyPoint>listB;
    
    //建立值和坐标的映射关系
    //这是是设计坐标从1开始的
    //如果想让坐标从0开始,i不用+1
    for(int i=0;i<lensA;i++)
    {
        mypoint.val=stof(strlistA[i]);
        mypoint.index=i+1;
        listA.push_back(mypoint);
    }

     for(int i=0;i<lensB;i++)
    {
        mypoint.val=stof(strlistB[i]);
        mypoint.index=i+1;
        listB.push_back(mypoint);
    }
    //根据值得的大小进行排序
    sort(listA.begin(),listA.end(),sortRegular);
    sort(listB.begin(),listB.end(),sortRegular);
    float sum=0;
    for(auto i:listB)
    {
        sum+=i.val;
    }
    bool flags[4]={0};

    vector<vector<MyPoint>>ans;
    vector<bool>tag(listA.size(),false);
    //计算得到listA的所有子序列,保存到ans中
    getSubsets(listA,tag,0,ans);

    //sumArray保存a不同的子集的和
    vector<float>sumArray;
    //计算每个子集对应的和
    getSumArray(sumArray,ans);
    float bestSum;
    int bestIndex;
    vector<compearStrust>saveList;
    
    //寻找最佳的分配方法
    searchBestChiose(ans,sumArray,sum,saveList,listB);
    cout<<"得到的物料分配关系:"<<endl;
    for(auto it:saveList)
    {
        cout<<it.valB<<" "<<it.indexA<<" "<<it.valA<<endl;
    }
    
    //将最佳的分配策略输出的output.txt中
    printResult(saveList);
}

动态演示

在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值