求解约束化问题
题目描述:
如何节省工料的约束化问题,其中集合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,只能重新挑选满足其长度要求的单个值。
那么我便来理清一下我的思路:
- 读取文件的内容
- 将字符串的内容提取到数组中去,这样方便处理
- 建立值和下标的映射关系
- 计算数组存在的所有子集
- 计算所有子集的和
- 跟B所需的物料进行比较得出最小的物料消耗
- 寻找最优的A里的元素分配给B里的元素的分配方式
- 当A中的最优分配方式中,一种物料不能完全满足,需要外借,将这种剔除。重新寻找最优的分配方式,直到找到为止
- 将找到的最优分配方式保存在结构体容器中,然后输出即可。
代码实现
#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);
}
动态演示