遗传算法解一道笔试题
来源:互联网 发布:linux如何创建文件夹 编辑:程序博客网 时间:2024/05/19 14:56
题目大意如下:
有N个房间,通过N-1个门相连(每个房间的门数在1到3之间),现在有M个路由器,需要把M个路由器放置在其中一些房间中,使得放置路由和其周围的房间能收到wifi信号(假如一个房间放置了路由器,只有它自己以及与它相邻的房间可以收到它的信号)。每个房间都有一个满意度,如果 该房间可以收到WiFi信号则,总的满意度就会累加上该房间的满意度。现在问,怎样放置M个路由器使得总满意度最大。
输入:
第一行两个整数N M,代表N个房间M个路由器,(2<=N<=1000, 1<=M<=N, M<=100)
第二行N个数,代表每个房间满意度
接下来N-1行,表示N-1个门,其中每行两个整数,代表门联通的房间号
输出:
最大满意度
样例输入:
5 11 2 3 4 52 13 24 25 37 11 2 3 4 5 6 72 13 24 25 36 27 47 21 2 3 4 5 6 72 13 24 25 36 27 48 21 2 3 4 5 6 7 82 13 24 25 36 27 48 5
样例输出:
162329
分析:首先将题目抽象成N个节点的树,房间为节点,门为边,节点的权值为满意度,接下来从中选择M节点,让它覆盖的权最大。
从N个点中选M个点,有C(N,M)种,可以从两个方面考虑
1.考虑树中的非叶子结点num,分两种情况:
如果num<=M,直接选取非叶子结点放置,如果有剩余则再随便放在叶节点,这样能满足所有房间全覆盖;满意度为所有房间之和。
如果num>M,这种情况比较复杂,我也没分析明白
2.直接用遗传算法解决,每个房间有一个编号,从中选择M个房间。对于基因的编码有两种考虑,这两种方法导致的复杂度相差很大。
(1)染色体长度为M,每一个基因分别代表选中的房间号,整个编码长度较短,交叉复杂度较低。例如:N=9,M=5时 染色体可能为:2 6 3 7 1
(2)染色体长度为N,每一个基因代表一个房间,如果选中则相应位置为1,否则为0。例如:N=9,M=5染色体可能为011100110
下面的遗传算法是采用第一种编码方法:
(之前也写过遗传算法,这次写完好像纠正了一些理解上的偏差)
#include <iostream>#include <vector>#include <algorithm>#include <cmath>#include <ctime>#include <fstream>#include <iterator>#include <cstring>#define MAX 0x37777777#define LEN 1002using namespace std;//遗传参数double PC=0.8 ; //交叉概率double PM=0.2 ; //变异概率const int H=9 ; //种群规模int G=1000 ; //迭代次数int N;int M;double S[LEN];//graph parameterint cnt=0;struct Edge{ int v,next;}edge[2*LEN];int head[LEN];struct Answer{ double fit; bool gen[LEN]; int chNodes[LEN];};vector<Answer> Popu;void addEdge(int u,int v)//邻接表(头插法){ edge[cnt].v=v; edge[cnt].next=head[u];head[u]=cnt++;}bool Cmp(const Answer & a1,const Answer & a2){ return a1.fit>a2.fit;}void initInput(){ memset(head,-1,sizeof(head)); cin>>N>>M; for(int i=0;i<N;i++) { cin>>S[i]; } for(int i=0;i<N-1;i++) { int u,v; cin>>u>>v; u--,v--;//下标从0开始 addEdge(u,v); addEdge(v,u); } //cout<<"input"<<endl;}void fitness(Answer &newGen){ int coverNodes[LEN]={0}; newGen.fit=0; for(int j=0;j<M;j++) { int node=newGen.chNodes[j]; coverNodes[node]=1; for(int e=head[node];e!=-1;e=edge[e].next) { int v=edge[e].v; if(coverNodes[v]!=1) { coverNodes[v]=1; } } } for(int j=0;j<N;j++) { if(coverNodes[j]==1) { newGen.fit+=S[j]; } }}void initPopu(){ for(int i=0;i<2*H;i++) { Answer newGen; newGen.fit=0; memset(newGen.gen,0,sizeof(newGen.gen)); memset(newGen.chNodes,0,sizeof(newGen.chNodes)); for(int j=0,k=0;j<M;) { int rom=rand()%N; if(newGen.gen[rom]!=1) { newGen.gen[rom]=1; newGen.chNodes[k]=rom; k++; j++; } } fitness(newGen); Popu.push_back(newGen); } //cout<<"initPopu"<<endl;}void choosePopu(){ vector<Answer> newPopu; double sumFits=0; double fits=0; for(int j=0;j<Popu.size();j++) { sumFits+=(1.0/Popu[j].fit); } for(int i=0;i<H-1;i++) { double random=(rand()%998)/997.0; fits=0; int num=0; for(int j=0;j<Popu.size();j++) { fits+=(1.0/Popu[j].fit/sumFits); if(fits>=random) { num=j;//选中num break; } } newPopu.push_back(Popu[num]); } sort(Popu.begin(),Popu.end(),Cmp); newPopu.push_back(Popu[0]);//精英选择,插在最后 swap(Popu,newPopu);}void cross1(int first,int second)//单点交叉{ Answer n1=Popu[first],n2=Popu[second]; int r1=rand()%M; int r2=rand()%M; if(r1==r2)return; else if(r1>r2) { r1=r1^r2; r2=r1^r2; r1=r1^r2; } int parent1[LEN]; int parent2[LEN]; memset(parent1,-1,sizeof(parent1)); memset(parent2,-1,sizeof(parent2)); for(int j=r1;j<r2;j++) { parent1[j]=n1.chNodes[j]; parent2[j]=n2.chNodes[j]; } for(int j=r1;j<r2;j++) { if(n1.gen[parent2[j]]==0) { n1.gen[parent2[j]]=1; n1.gen[parent1[j]]=0; n1.chNodes[j]=parent2[j]; } } for(int j=r1;j<r2;j++) { if(n2.gen[parent1[j]]==0) { n2.gen[parent1[j]]=1; n2.gen[parent2[j]]=0; n2.chNodes[j]=parent1[j]; } } fitness(n1); Popu.push_back(n1); fitness(n2); Popu.push_back(n2);}void xCross(){ for(int i=0;i<H;i++) { double random=(rand()%998)/997.0; if(random<PC) { int first=i; int second=(i+(rand()%(H-1)))%(H); //交叉 cross1(first,second); } }}void verify()//变异{ for(int i=H;i<Popu.size();i++) { double random=(rand()%998)/997.0; if(random<PM) { Answer nv=Popu[i]; int del=rand()%M; int delNode=nv.chNodes[del]; int add=rand()%N; while(nv.gen[add]!=0) { add=rand()%N; } nv.gen[delNode]=0; nv.gen[add]=1; nv.chNodes[del]=add; fitness(nv); Popu.push_back(nv); } }}void GA(){ initPopu();//初始化种群 int k=0;//第k代数 for(;k<G;k++) { //选择(精英选择1+轮盘选择) choosePopu(); //交叉 xCross(); //变异 verify(); //cout<<k<<":"<<(Popu[0]).fit<<endl;//第k次迭代最好代价 } sort(Popu.begin(),Popu.end(),Cmp); //Save(Popu[0]); //copy((Popu[0]).path.begin(),(Popu[0]).path.end(),ostream_iterator<int>(cout," "));cout<<endl;//输出answer cout<<(Popu[0]).fit<<endl;}int main(){ srand ( unsigned (time(NULL) ) ); initInput(); GA(); return 0;}
- 遗传算法解一道笔试题
- 一道算法笔试题
- 一道算法笔试题
- 一道求职笔试题:c#算法题
- 从一道笔试题谈算法优化
- 《从一道笔试题谈算法优化》
- 从一道笔试题谈算法优化
- 从一道笔试题谈算法优化
- 从一道笔试题谈算法优化
- 从一道笔试题谈算法优化
- 一道微软笔试题,算法才是王道
- 一道java笔试题------字符串压缩算法
- 阿里巴巴一道笔试算法题分析…
- 一道有道实习生笔试算法题分析
- 从一道笔试题谈算法优化
- 今天笔试的一道算法题,每次都吃后悔药,痛苦!
- 从一道笔试题谈算法优化(上)
- 从一道笔试题谈算法优化(下)
- MySQL中索引的创建与使用
- 扩展ElasticSearch:实现分片并可用于存储亿万文档的实践
- nodejs简介
- 入职必备,Android 真实面试题(内有答案)
- linux网络编程之TCP/IP基础(二):利用ARP和ICMP协议解释ping命令
- 遗传算法解一道笔试题
- 从chrome源码到xilium.CefGlue集成注意事项
- Java代码规范总结
- linux网络编程之TCP/IP基础(三):IP数据报格式和IP地址路由
- Clojure介绍、安装和语法
- linux网络编程之TCP/IP基础(四):TCP连接的建立和断开、滑动窗口
- 划分无冲突子集问题
- 【分享】10个帮你修图+剪辑视频+PPT制作的网站
- Android 自定义进度条