【算法】HDOJ-1016 Prime Ring Problem
来源:互联网 发布:网络7层协议 编辑:程序博客网 时间:2024/05/18 01:49
PrimeRing Problem
TimeLimit: 4000/2000 MS (Java/Others) MemoryLimit: 65536/32768 K (Java/Others)
Total Submission(s):16943 Accepted Submission(s): 7699
ProblemDescription
Aring is compose of n circles as shown in diagram. Put natural number1, 2, ..., n into each circle separately, and the sum of numbers intwo adjacent circles should be a prime.
Note: the number offirst circle should always be 1.
Input
n(0 < n < 20).
Output
Theoutput format is shown as sample below. Each row represents a seriesof circle numbers in the ring beginning from 1 clockwisely andanticlockwisely. The order of numbers must satisfy the aboverequirements. Print solutions in lexicographical order.
Youare to write a program that completes above process.
Print ablank line after each case.
SampleInput
68
SampleOutput
Case 1:1 4 3 2 5 61 6 5 2 3 4Case 2:1 2 3 8 5 6 7 41 2 5 8 3 4 7 61 4 7 6 5 8 3 21 6 7 4 3 8 5 2
My code:
//1016_2.cpp
//最初的想法,遍历出每一种情况,判断相邻数之和是否为素数。执行效率非常低,运行超时
#include<iostream>using namespace std;int main(){ void case_bool_cout(int count,int n,int num[]); int n,count,num[100]={0}; num[0]=1; while(cin>>n){ count=1; case_bool_cout(count,n,num); } return 0;}void case_bool_cout(int count,int n,int num[100]){ bool repeat(int,int num[]); int i,j; bool case_prime(int n,int num[]); if(count==n){ //执行到最后,产生了一种情况 if( repeat(n,num) ) ; //判断数组中是否有重复的数 else if( case_prime(n,num) ){ //没有重复的,接着判断,是否符合 相邻两数和为素数的 条件 for(j=0;j<n;j++) //都符合,输出这种情况 cout<<num[j]<<' '; cout<<endl; } } else{ //情况产生中 for(j=2;j<=n;j++){ //循环该位上可能的数 num[count]=j; case_bool_cout(count+1,n,num); //count表示循环到哪一位了 } } }bool case_prime(int n,int num[100]) //判断该种情况是否符合题目要求,即相邻两数和为素数。{ int s,i; bool num_prime(int n); //判断一个整数是否为素数 bool f; f=true; for(i=0;i<n;i++){ //循环判断这种情况下相邻两数和是否为素数 if(i==n-1) s=num[0]+num[i]; else s=num[i]+num[i+1]; if( ! num_prime(s) ) {f=false; break;} //如果有一个不是素数,表示这种情况不符合要求,跳出循环 } return f;}bool num_prime(int n){ bool f=true; int i; for(i=2;i<n;i++) if(n%i==0) {f=false;break;} return f;}bool repeat(int n,int num[100]){ int i,j; for(i=0;i<n-1;i++) for(j=i+1;j<n;j++) if(num[i]==num[j]) return true; return false;}
//1016_3.cpp
//提交通过,但是效率不高,且占用空间大。
//Pro.ID Exe.Time Exe.Memory CodeLen. Language
//1016 859MS 340K 2039B C++
//经过改进,运用了临接矩阵表列出所有情况,储存在二维数组中,之后就是从中搜索出符合条件的情况,输出。但是运行时间还是较长,未经过优化。
#include<iostream>usingnamespace std;intprime_table[19][19] = {{1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0},{1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0},{0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0},{1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1},{0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0},{1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0},{0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0},{0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0},{0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0},{1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1},{0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0},{1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1},{0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0},{0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0},{0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0},{1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0},{0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0},{1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1},{0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0}};intcount=0;intmain(){voidergod(int ,int [19],int );intdigit=1,n,queen[19]={0};while(cin>>n){count++;digit=1;queen[0]=1; //首先给队列里第一个数赋值 1cout<<"Case"<<count<<':'<<endl;if(n==1)cout<<endl;else{ergod(digit,queen,n);//遍历所有情况,如果符合条件,输出。cout<<endl;}}return0;}voidergod(int digit,int queen[19],int n) //确定第digit位的数{boolf; //true表示不重复inti,j;if(digit< n) //位数还没判断到最后一位,继续本位数的遍历。for(j=0;j<n;j++){ //j代表与本位相邻的下一位数f=true;if(prime_table[queen[digit-1]-1][j]== 1){ //如果刚才那位的数与下一位数和是质数,继续执行。for(i=0;i<digit;i++) //循环数组,判断该数与之前各位数有没有重复if(j+1==queen[i]){f=false;break;}if(f==true){ //没有重复queen[digit]=j+1;ergod(digit+1,queen,n);}}}else{ //到最后了,输出这种情况if(prime_table[0][queen[n-1]-1] ==1 ){for(j=0;j<n;j++){if(j==n-1)cout<<queen[j];elsecout<<queen[j]<<'';}cout<<endl;}}}
//1016_4.cpp
//经过了优化
//Pro.ID Exe.Time Exe.Memory CodeLen. Language
//1016 296MS 252K 1742B G++
//优化:
//将输入输出头文件iostream换成了stdio.h
//将所有输入输出的cin,cout换成scanf,printf,因为这样输入输出效率很高
//删掉了所有注释
//这样运行时间一下子降低了500+MS,代码长度也降低了一点。
#include<stdio.h>usingnamespace std;intprime_table[19][19] = {{1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0},{1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0},{0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0},{1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1},{0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0},{1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0},{0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0},{0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0},{0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0},{1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1},{0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0},{1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1},{0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0},{0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0},{0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0},{1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0},{0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0},{1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1},{0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0}};intcount=0;intmain(){voidergod(int ,int [19],int );intdigit=1,n,queen[19]={0};while(scanf("%d",&n)!=EOF){count++;digit=1;queen[0]=1;printf("Case%d:\n",count);if(n==1)printf("\n");else{ergod(digit,queen,n);printf("\n");}}return0;}voidergod(int digit,int queen[19],int n){boolf;inti,j;if(digit< n)for(j=0;j<n;j++){f=true;if(prime_table[queen[digit-1]-1][j]== 1){for(i=0;i<digit;i++)if(j+1==queen[i]){f=false;break;}if(f==true){queen[digit]=j+1;ergod(digit+1,queen,n);}}}else{if(prime_table[0][queen[n-1]-1] ==1 ){for(j=0;j<n;j++){if(j==n-1)printf("%d",queen[j]);elseprintf("%d",queen[j]);}printf("\n");}}}
算法分析:
这道题我开始的想法很简单,就是枚举一遍,其实后面的也是遍历出所有适合的情况,只不过开始的算法写的很笨拙,以致效率很低。后来经过老师指点,看了《算法导论》图论那方面的知识,加上请教学长,最后用临接矩阵表解决了这个问题。临接矩阵表是我直接列出,放到代码里,这样不用再写代码去求矩阵表,相当于用空间复杂度去换时间复杂度,变相的降低了难度。但是如果n给的范围很大,我就不可能把所有情况都列到代码里,所以我想后面还可以改进,将求临接矩阵表的函数写出来。关于这方面,老师今天有过指导,可以用筛法求矩阵,先把范围内的素数列出来,然后写个循环,用这个素数减去循环变量,求出另一半,而且只需计算到一半即可。
而后面的算法,也可以试试用分支定界法求解。这题里我用的是回溯法,回溯法是深度优先算法,效率低,空间占用少。而分支定界法是广度优先算法,效率高,空间占用多。
这个问题放到后面的学习中再深入研究,这道题就先这样。
这里给出关于分支定界法的相关资料,便于以后深入:
百度百科-分支定界法:http://baike.baidu.com/view/587272.htm
百度百科-分支限界法:http://baike.baidu.com/view/587272.htm
分支定界(branchand bound) 算法:http://bbs.ednchina.com/BLOG_ARTICLE_213865.HTM
- 【算法】HDOJ-1016 Prime Ring Problem
- HDOJ 1016 Prime Ring Problem!!
- HDOJ 1016 Prime Ring Problem
- HDOJ 1016 Prime Ring Problem
- hdoj 1016 Prime Ring Problem
- 【HDOJ 1016】Prime Ring Problem
- hdoj 1016 Prime Ring Problem
- hdoj 1016 Prime Ring Problem
- HDOJ 1016 Prime Ring Problem
- HDOJ-【1016 Prime Ring Problem】
- hdoj-1016 Prime Ring Problem
- hdoj 1016 Prime Ring Problem
- HDOJ 1016 Prime Ring Problem 简单搜索
- hdu/hdoj 1016 Prime Ring Problem
- hdoj 1016 Prime Ring Problem 【DFS】
- HDOJ 1016 Prime Ring Problem DFS
- HDoj-1016-Prime Ring Problem-DFS
- hdoj 1016 Prime Ring Problem【DFS】
- 浮点指令
- 服务端Too many open files解决方案
- Android 如何看日志信息
- ArcGIS API for Silverlight 实现修改地图上的工程点位置 .
- JSP下动态INCLUDE与静态INCLUDE的区别,Forward和Redirect的区别分析
- 【算法】HDOJ-1016 Prime Ring Problem
- Ubuntu10.10 64位编译安装最新git
- 方差,协方差,协方差矩阵
- Example4_13
- 数据结构(C#)-- 贪心算法解决背包问题
- 优酷视频真实地址解析
- 测试质量概念散文(一)
- POJ3356
- 从spring获得connection 并且是打开的