Code Jam--The Bored Traveling Salesman
来源:互联网 发布:nt数据看宝宝男女最准 编辑:程序博客网 时间:2024/05/16 15:47
原题:https://code.google.com/codejam/contest/2994486/dashboard#s=p2
官方题解:https://code.google.com/codejam/contest/2994486/dashboard#s=a&a=2
题意:给定一个规模为N的无向连通图,每个点有一个5位10进制数的邮政编码,当遍历这个图时我们把访问到的zip按先后顺序连接起来可以形成一个5*N位的数,问能行成的最小数。其中遍历时前向进入某个点的道路只能使用一次,返回某点的次数不受限制。
题解:注意到起始点必定是zip最小的点,因为在无向图中,一个点若能到其它任何点,则从此点出发肯定能按照题意即将每个边前向后向遍历一次且能遍历所有点。首先这个结论在两层的无向连通树里面是显然成立的,然后可以用归纳法证明我们通过遍历由zip最小的点到达所有点的DFS生成树,可以遍历所有点且前向边和其反向边只用一次(其实正是DFS及其返回的过程)。
- 一开始只用到了起始点的贪心,再用可返回父节点的DFS搜所有可能的路径复杂度(N-1)!。看了题解才明白是可以一直用贪心思想的。我们将N个点动态分配为:minpath[],active[]。其中minPath保存已知最优答案的zip各点,active保存已知最优且还能返回再访问的点,因为在路径中可能返回则返回的点我们不会再访问。
- **找到栈active所有点的邻接点中能到达剩下所有点且zip最小的点。
- 从active栈顶的点的邻接点开始,其中我们仍然使用最初的贪心思想,看它DFS能访问到多少个其他点,若还不足以到达所有点,则我们必须层层返回active中的点看它们是否能到达剩下的点。
- 当栈顶的点的所有邻接点已经验证完毕时,这时我们就要看倒数第二个进入active的点的邻接点,即可能的路径为从最后进入active的点返回倒数第二个点。
- 。。。
- 若最优的点不是active栈顶的点的邻接点,则我们一直出栈直到最优的那个点的父节点,然后将最优点放入栈中,重复步骤1直到minPath的容量达到N。
#include<iostream>#include<cstdio>#include<cstring>#include<vector>using namespace std;#define INF 0X7F7F7F7Fclass solve{private: int N; int M; int t; int zip[51]; int minPath[51]; int active[51]; char InPath[51]; int activeNum; int tmpActiveNum; int pathLen; int start; char reachGraph[51][51]; vector<vector<int> > g;public: solve(int i):t(i) { memset(reachGraph,0,sizeof(reachGraph)); processIn(); calcMinZip(); printf("Case #%d: ",t); for(int i = 0;i < N;i++) { printf("%d",minPath[i]); } printf("\n"); } int processIn(); int calcMinZip(); bool IsReachAll(int nodeNo); int DFS(int nodeNo,int* reachNodeNum,char* vis);};int solve::DFS(int nodeNo,int* reachNodeNum,char* vis){ if(*reachNodeNum == N) return 1; int adjSize = g[nodeNo].size(); int nextNode; for(int i = 0; i < adjSize;i++) { nextNode = g[nodeNo][i]; if(!InPath[nextNode]&&!vis[nextNode]) { vis[nextNode] = 1; (*reachNodeNum)++; DFS(nextNode,reachNodeNum,vis); } } return 1;}bool solve::IsReachAll(int nodeNo){ int reachNodeNum = pathLen+1; char vis[51]; memset(vis,0,sizeof(vis)); for(int i = tmpActiveNum;i >= 0;i--) { if(i == tmpActiveNum) { DFS(nodeNo,&reachNodeNum,vis); //直接从nodeNo能访问到的其他点 } else { DFS(active[i],&reachNodeNum,vis); //从nodeNo往回走到其它active点再访问到的其他点 } if(reachNodeNum == N) return 1; } return 0;}int solve::calcMinZip(){ int minZip; int minZipIndex; int bestActiveNum; activeNum = 0; active[activeNum++] = start; memset(InPath,0,sizeof(InPath)); InPath[start] = 1; pathLen = 0; minPath[pathLen++] = zip[start]; while(pathLen < N) { tmpActiveNum = activeNum; minZip = INF; for(int i = activeNum-1;i >= 0;i--) //active数组减小表示要先往回走,再到达我们要求的下一个点 { tmpActiveNum = i+1; for(int j = 1;j <= N;j++) //遍历active数组中点的邻接点,找出zip最小且通过路径能到达所有其他点的点 { if(InPath[j]) continue; if(reachGraph[active[i]][j]) { InPath[j] = 1; if(minZip > zip[j]&&IsReachAll(j)) //zip比已知的小才进行搜索看能否到其他所有点 { minZip = zip[j]; minZipIndex = j; bestActiveNum = tmpActiveNum; } InPath[j] = 0; } } } activeNum = bestActiveNum; //更新active数组大小,则有些点再也不会访问到 active[activeNum++] = minZipIndex; minPath[pathLen++] = minZip; InPath[minZipIndex] = 1; } return 1;}int solve::processIn(){ scanf("%d%d",&N,&M); int a,b; int minZip = INF; g.resize(N+1); for(int i = 1;i <= N;i++) { scanf("%d",zip+i); if(minZip > zip[i]) { minZip = zip[i]; start = i; } } while(M--) { scanf("%d%d",&a,&b); reachGraph[a][b] = reachGraph[b][a] = 1; g[a].push_back(b); g[b].push_back(a); } return 0;}int main(){ int T; scanf("%d",&T); for(int i = 1;i <= T;i++) { solve the_bored_traveling_salesman(i); } return 0;}
0 0
- Code Jam--The Bored Traveling Salesman
- The Traveling Salesman Problem
- Code Jam--The Repeater
- Poj3033 Traveling Salesman(搜索)
- [Code Jam] Bribe the Prisoners
- Visualisation of Genetic Algorithms for the Traveling Salesman Problem in Java --by Johannes Sarg
- The Salesman
- google code jam 2008 Saving the Universe
- Traveling Salesman Problem-Statement of work
- Solution to Bitonic Euclidean Traveling-salesman Problem
- Program work 9. Traveling salesman problem (TSP)
- Google code jam 2008 beta B The Price is Wrong
- Google Code Jam Notes - Cross The Maze - Java
- 双调旅行商问题 Bitonic Traveling Salesman Problem
- Google Code Jam 2006
- Google China Code Jam
- code.jam - pixelcanvas
- code.jam - egg drops
- (转载)linux命令之一ls命令
- ubuntu 上安装 selinux总结
- 爱网购,爱赚钱。 兼职也是不错的。
- LeetCode:Fraction to Recurring Decimal
- Oracle 游标详解
- Code Jam--The Bored Traveling Salesman
- oracle常用的数据库锁定语句
- xstream 别名的用法
- Unity3D(二)用反射、泛型读取XML后动态创建实例并赋值
- Java web----JavaBean
- Android 几种SharePreference的使用
- myeclipse 自动添加头时间,作者,文件注释等信息
- 数据收集与分析:可穿戴设备的真正意义
- VC2008 Windows Media Player控件的使用技巧