Description
Here is no naked girl nor naked runners, but a naked problem: you are to find the K-th smallest element in the set of all irreducible fractions , with 0<p<q≤N.
Input
The first line of input is an integer T(T≤1000), indicated there are T cases in the file.
For each cases, there is one line with two positive integers N and K.(1≤K<N≤1000000)
Output
For each case, output a line containing answer.
Sample Input
4
5 1
5 2
5 3
5 4
Sample Output
1/5 1/4 1/3 2/5
昨天陶叔告诉我直接暴力DFS,我当时推出个规律是,最小的一定是 1/n,然后1/n和2/n中间隔着一些分母比n小的分数,我一开始觉得这些分数就是1/(n-1)..(n-i),照此规律,前几个数是可以满足的,后来发现错了,i/n和i+1/n之间隔的分数不可能就是这样能枚举出来,还有一些分子比i大的同样可以存在于里面,所以这个DFS宣告失败。
后来看了下别人代码,发现有个规律就是 1/(n)一定比1/(n-1)小,而 2/(n)一定是比 1/(n-1)大,所以通过这个构建子树,从 1/2开始先向左扩张,找到最小的(即 1/n),然后回退找到父亲那里就是次小的,然后搜右子树,。。其实就是个中序遍历就可以了。
发现写完后,给个符合题目要求的比较大的数据程序直接崩了,我cout了一下,发现是dfs栈开不了那么多,但是在OJ上是可以成功运行的,所以有时候本机会崩的程序好像OJ不一定会崩,别看到大数据本机运行崩了就以为通不过OJ
#include <iostream> #include <cstdio> using namespace std; int n,k; struct node { int p,q; node operator+(const node &rhs) { node nt; nt.p=p+rhs.p; nt.q=q+rhs.q; return nt; } }; node ans; bool dfs(node f1,node f2) { if (k==0) return 1; node nf=f1+f2; if (nf.q>n) return false;//边界设置 //cout<<nf.q<<" "<<n<<endl; bool flag=dfs(f1,nf); //cout<<nf.q<<endl; if (flag) return 1; if (!flag) { k--;//搜到边界就说明该数肯定为接下来要找的这个次序的值 if (k==0){ ans=nf; return 1; } } return dfs(nf,f2); } int main() { //std::ios::sync_with_stdio(false); //freopen("naked.in","r",stdin); //freopen("csu_b.out","w",stdout); int t; scanf("%d",&t); while (t--) { scanf("%d%d",&n,&k); node f=(node){0,1}; //通过f和nf控制向左子树和右子树走 node nf=(node){1,1}; //cout<<" pass"<<endl; dfs(f,nf); printf("%d/%d ",ans.p,ans.q); } return 0; }
我发现自己代码规范写的真差,今天铁哥也讲了这个,确实要改进