一步之遥
从昏迷中醒来,小明发现自己被关在X星球的废矿车里。
矿车停在平直的废弃的轨道上。
他的面前是两个按钮,分别写着“F”和“B”。
小明突然记起来,这两个按钮可以控制矿车在轨道上前进和后退。
按F,会前进97米。按B会后退127米。
透过昏暗的灯光,小明看到自己前方1米远正好有个监控探头。
他必须设法使得矿车正好停在摄像头的下方,才有机会争取同伴的援助。
或许,通过多次操作F和B可以办到。
矿车上的动力已经不太足,黄色的警示灯在默默闪烁...
每次进行 F 或 B 操作都会消耗一定的能量。
小明飞快地计算,至少要多少次操作,才能把矿车准确地停在前方1米远的地方。
请填写为了达成目标,最少需要操作的次数。
注意,需要提交的是一个整数,不要填写任何无关内容(比如:解释说明等)
#include<cstdio> #include<algorithm> #include<iostream> using namespace std; int main(void) { int Min = 0xFFFFFFF; for(int i=0;i<=1000;i++) for(int j=0;j<=1000;j++) if(97*i-127*j==1 && i+j<Min) { Min = i + j; } cout << Min ; return 0; }
凑平方数
把0~9这10个数字,分成多个组,每个组恰好是一个平方数,这是能够办到的。
比如:0, 36, 5948721
再比如:
1098524736
1, 25, 6390784
0, 4, 289, 15376
等等...
注意,0可以作为独立的数字,但不能作为多位数字的开始。
分组时,必须用完所有的数字,不能重复,不能遗漏。
如果不计较小组内数据的先后顺序,请问有多少种不同的分组方案?
注意:需要提交的是一个整数,不要填写多余内容。
这个方法是参考网上的方法,思路是首先使用全排列得到各种可能的组合,然后对于一个特定的序列组合,找到可能的平方数组合,为了防止重复,这里规定一个序列组合中的平方数只能从小到大进行排列。
#include<iostream> #include<cstdio> #include<map> #include<algorithm> typedef long long LL; using namespace std; int s[10]={0,1,2,3,4,5,6,7,8,9}; int ans; map<LL,int>mp; void dfs(LL ss,int x) { if(x==10) { cout << ans << endl; ans++; return ; } if(s[x]==0) { if(x==0) dfs(0,x+1); return ; } LL sum=0; for(int i=x;i<10;i++) { sum=sum*10+s[i]; if(sum>ss && mp[sum]) dfs(sum,i+1); } } int main(void) { for(LL i=0;i<=500000;i++) mp[i*i]=1; do{ dfs(-1,0); }while(next_permutation(s,s+10)); cout << ans << endl; return 0; }
这是我自己重新写了一下的方法,但是一直结果不正确,后来终于发现了原因。
#include<map> #include<iostream> #include<cstdio> #include<algorithm> using namespace std; typedef long long LL; map<LL,int>mp; int a[10],sum=0; void DFS(LL pre,int cur) { if(cur==10) { sum++; return ; } if(a[cur]==0 ) { if(cur==0) DFS(0,cur+1); return ; } else { LL s = 0; for(int i=cur;i<10;i++) { s=s*10+a[i]; if(s>pre && mp[s]) DFS(s,i+1); } } } int main(void) { for(int i=0;i<10;i++) a[i]=i; for(int i=0;i<=500000;i++) mp[i*i]=1; do{ DFS(-1,0); }while(next_permutation(a,a+10)); printf("sum = %d ",sum); return 0; }
//eg.这里再初始化的时候i*i首先是保存为int,然后再转换为long long,因此这里越界了,
//应该写成for(long long i=0;i<=500000;i++) mp[i*i]=1;
这个是我的方法,首先也是全排列,然后对于每一个序列,找到他的所有的平方数的组合,注意此时不需要进行从小到大的排列。然后把每一个序列的平方数组合情况放到一个set中,这样就能够实现自动的排序,然后再使用一个集合set,这样就可以实现去除重复。
#include<iostream> #include<cstdio> #include<cmath> #include<set> #include<algorithm> const int eps = 10e-8; using namespace std; int a[10]; set<set<long long> >se; set<long long>Sqrtn; void DFS(int i,long long b[],int n) { if(i==10) { set<long long> s; for(int i=0;i<n;i++) s.insert(b[i]); se.insert(s); return ; } long long s = 0; int first = 1; while(i<=9) { s=s*10+a[i]; if(a[i]==0 && first==1) { b[n]=0; DFS(i+1,b,n+1); break; } first = 0; //直接开放计算 long long sqrtn = (long long )(sqrt(s*1.0)+0.5); if(sqrtn * sqrtn == s) { b[n]=s; DFS(i+1,b,n+1); } /* 使用集合计算 if(Sqrtn.find(s) != Sqrtn.end()) { b[n]=s; DFS(i+1,b,n+1); } */ i++; } } int main(void) { long long b[10]; for(int i=0;i<10;i++) a[i]=i; for(long long i=0;i<=100000;i++) Sqrtn.insert(i*i); do { //for(int i=0;i<10;i++) printf("%d",a[i]); //printf(" "); DFS(0,b,0); }while(next_permutation(a,a+10)); for(set<set<long long> >::iterator it = se.begin();it!=se.end();it++) { set<long long> s = *it; for(set<long long >::iterator x=s.begin();x!=s.end();x++) { printf("%lld ",*x); } printf(" "); } cout << "sum = " << se.size()<<endl; return 0; }
输出如下:
0 1 4 9 872356 0 1 4 3297856 0 1 4 3857296 0 1 4 5827396 0 1 4 6385729 0 1 4 8567329 0 1 4 9572836 0 1 9 25 36 784 0 1 36 529 784 0 1 49 872356 0 1 64 537289 0 1 256 73984 0 1 625 73984 0 4 16 537289 0 4 25 81 7396 0 4 25 139876 0 4 25 391876 0 4 289 15376 0 9 25 361 784 0 9 81 324 576 0 9 324 15876 0 9 13527684 0 9 34857216 0 9 65318724 0 9 73256481 0 9 81432576 0 16 25 73984 0 16 784 5329 0 25 784 1369 0 25 784 1936 0 25 841 7396 0 36 81 74529 0 36 81 79524 0 36 729 5184 0 36 5184729 0 36 5948721 0 81 324 7569 0 81 576 3249 0 81 729 4356 0 81 2537649 0 81 5673924 0 81 7436529 0 81 9253764 0 324 751689 0 361 529 784 0 576 321489 0 576 349281 0 576 381924 0 729 385641 0 3249 15876 0 4356 71289 0 8649 35721 0 139854276 0 152843769 0 157326849 0 215384976 0 245893761 0 254817369 0 326597184 0 361874529 0 375468129 0 382945761 0 385297641 0 412739856 0 523814769 0 529874361 0 537219684 0 549386721 0 587432169 0 589324176 0 597362481 0 615387249 0 627953481 0 653927184 0 672935481 0 697435281 0 714653289 0 735982641 0 743816529 0 842973156 0 847159236 0 923187456 1 4 9 36 87025 1 4 9 7203856 1 4 9 8673025 1 4 68973025 1 4 85063729 1 4 86397025 1 4 98327056 1 9 25 760384 1 9 784 30625 1 25 36 47089 1 25 3748096 1 25 6390784 1 36 49 87025 1 36 784 9025 1 49 7203856 1 49 8673025 1 289 357604 1 529 760384 1 784 390625 1 784 635209 4 9 361 87025 4 25 81 30976 4 25 3798601 4 289 173056 4 1369 87025 4 1936 87025 4 2809 15376 4 3025 17689 4 3025 18769 4 3025 78961 4 3025 81796 4 5329 67081 9 16 784 3025 9 36 7851204 9 81 324 7056 9 81 576 2304 9 81 4730625 9 81 6734025 9 324 576081 9 576 408321 9 576 423801 9 1764 38025 9 2304 15876 9 4761 38025 9 5184 20736 9 5184 30276 9 6084 35721 9 102576384 9 105637284 9 158306724 9 176305284 9 180472356 9 183467025 9 187635204 9 208571364 9 218034756 9 284057316 9 307265841 9 316057284 9 430728516 9 472801536 9 475283601 9 560837124 9 570684321 9 576432081 9 734681025 9 783104256 9 825470361 9 853107264 16 784 93025 25 361 47089 25 784 39601 25 841 30976 36 81 257049 36 81 497025 36 81 725904 36 19847025 36 57108249 36 71520849 36 80514729 36 94187025 49 361 87025 81 576 23409 81 576 39204 81 729 63504 81 2304 7569 81 3249 7056 81 32970564 81 34257609 81 45239076 81 56972304 81 70459236 81 73925604 81 74390625 169 784 3025 196 784 3025 324 576 1089 324 576 9801 324 6517809 324 8590761 361 784 9025 576 1034289 576 1432809 576 2039184 576 2893401 576 3814209 576 9108324 729 3048516 729 4835601 729 5308416 784 961 3025 1764 893025 2304 751689 3249 576081 4761 893025 5184 207936 5184 603729 7056 321489 7056 349281 7056 381924 7569 408321 7569 423801 8649 731025 15876 23409 15876 39204 20736 51984 20736 95481 30276 51984 30276 95481 38025 47961 63504 71289 1026753849 1042385796 1098524736 1237069584 1248703569 1278563049 1285437609 1382054976 1436789025 1503267984 1532487609 1547320896 1643897025 1827049536 1927385604 1937408256 2076351489 2081549376 2170348569 2386517904 2431870596 2435718609 2571098436 2913408576 3015986724 3074258916 3082914576 3089247561 3094251876 3195867024 3285697041 3412078569 3416987025 3428570916 3528716409 3719048256 3791480625 3827401956 3928657041 3964087521 3975428601 3985270641 4307821956 4308215769 4369871025 4392508176 4580176329 4728350169 4730825961 4832057169 5102673489 5273809641 5739426081 5783146209 5803697124 5982403716 6095237184 6154873209 6457890321 6471398025 6597013284 6714983025 7042398561 7165283904 7285134609 7351862049 7362154809 7408561329 7680594321 7854036129 7935068241 7946831025 7984316025 8014367529 8125940736 8127563409 8135679204 8326197504 8391476025 8503421796 8967143025 9054283716 9351276804 9560732841 9614783025 9761835204 9814072356 sum = 300 -------------------------------- Process exited after 3.196 seconds with return value 0 请按任意键继续. . .
棋子换位
有n个棋子A,n个棋子B,在棋盘上排成一行。
它们中间隔着一个空位,用“.”表示,比如:
AAA.BBB
现在需要所有的A棋子和B棋子交换位置。
移动棋子的规则是:
1. A棋子只能往右边移动,B棋子只能往左边移动。
2. 每个棋子可以移动到相邻的空位。
3. 每个棋子可以跳过相异的一个棋子落入空位(A跳过B或者B跳过A)。
AAA.BBB 可以走法:
移动A ==> AA.ABBB
移动B ==> AAAB.BB
跳走的例子:
AA.ABBB ==> AABA.BB
以下的程序完成了AB换位的功能,请仔细阅读分析源码,填写划线部分缺失的内容。
#include <stdio.h> #include <string.h> void move(char* data, int from, int to) { data[to] = data[from]; data[from] = '.'; } int valid(char* data, int k) { if(k<0 || k>=strlen(data)) return 0; return 1; } void f(char* data) { int i; int tag; int dd = 0; // 移动方向 while(1){ tag = 0; for(i=0; i<strlen(data); i++){ if(data[i]=='.') continue; if(data[i]=='A') dd = 1; if(data[i]=='B') dd = -1; if(valid(data, i+dd) && valid(data,i+dd+dd) && data[i+dd]!=data[i] && data[i+dd+dd]=='.'){ //如果能跳... move(data, i, i+dd+dd); printf("%s ", data); tag = 1; break; } } if(tag) continue; for(i=0; i<strlen(data); i++){ if(data[i]=='.') continue; if(data[i]=='A') dd = 1; if(data[i]=='B') dd = -1; if(valid(data, i+dd) && data[i+dd]=='.'){ // 如果能移动... if( ______________________ ) continue; //填空位置 move(data, i, i+dd); printf("%s ", data); tag = 1; break; } } if(tag==0) break; } } int main() { char data[] = "AAA.BBB"; f(data); return 0; }
注意:只提交划线部分缺少的代码,不要复制已有代码或填写任何多余内容。
#include <stdio.h> #include <string.h> void move(char* data, int from, int to) { data[to] = data[from]; data[from] = '.'; } int valid(char* data, int k) { if(k<0 || k>=strlen(data)) return 0; return 1; } void f(char* data) { int i; int tag; int dd = 0; // 移动方向 while(1){ tag = 0; for(i=0; i<strlen(data); i++){ if(data[i]=='.') continue; if(data[i]=='A') dd = 1; if(data[i]=='B') dd = -1; if(valid(data, i+dd) && valid(data,i+dd+dd) && data[i+dd]!=data[i] && data[i+dd+dd]=='.'){ //如果能跳... move(data, i, i+dd+dd); printf("%s ", data); tag = 1; break; } } if(tag) continue; for(i=0; i<strlen(data); i++){ if(data[i]=='.') continue; if(data[i]=='A') dd = 1; if(data[i]=='B') dd = -1; if(valid(data, i+dd) && data[i+dd]=='.'){ // 如果能移动... /* if( ((valid(data,i-dd)&&data[i-dd]!=data[i])||!valid(data,i-dd)) && ((valid(data,i+dd+dd) && data[i+dd+dd]==data[i])||!valid(data,i+dd+dd)) && ((valid(data,i-dd-dd) && data[i-dd-dd]!=data[i])||!valid(data,i-dd-dd)) && ((valid(data,i+dd+dd+dd) && data[i+dd+dd+dd]==data[i])||!valid(data,i+dd+dd+dd)) ) continue; //填空位置,解决不正确停止的问题 */ move(data, i, i+dd); printf("%s ", data); tag = 1; break; } } if(tag==0) break; } } int main() { char data[] = "AAA.BBB"; f(data); return 0; }
#include <stdio.h> #include <string.h> void move(char* data, int from, int to) { data[to] = data[from]; data[from] = '.'; } int valid(char* data, int k) { if(k<0 || k>=strlen(data)) return 0; return 1; } void f(char* data) { int i; int tag; int dd = 0; // 移动方向 while(1){ tag = 0; for(i=0; i<strlen(data); i++){ if(data[i]=='.') continue; if(data[i]=='A') dd = 1; if(data[i]=='B') dd = -1; if(valid(data, i+dd) && valid(data,i+dd+dd) && data[i+dd]!=data[i] && data[i+dd+dd]=='.'){ //如果能跳... move(data, i, i+dd+dd); printf("%s ", data); tag = 1; break; } } if(tag) continue; for(i=0; i<strlen(data); i++){ if(data[i]=='.') continue; if(data[i]=='A') dd = 1; if(data[i]=='B') dd = -1; if(valid(data, i+dd) && data[i+dd]=='.'){ // 如果能移动... //如果data[i]元素前进方向的反方向的元素存在并且和data[i]不同 //并且data[i]元素请进方向的前方第二个位置元素存在并且和data[i]相同,那么停止这一次移动。 //没有可以跳的 该棋子可移动之前 判断它旁边字母是否与他相同 若相同则移动 //若不同 则说明这是刚刚跳过来的 在判断“ . ”后面可还有字母 若有判断与该棋子旁边的旗子是否相同 若相同则说明不该这一旗子移动 continue 过去 if(valid(data, i-dd) && data[i-dd]!=data[i]&& valid(data, i+dd+dd) && data[i+dd+dd]==data[i-dd]) continue; //填空位置 move(data, i, i+dd); printf("%s ", data); tag = 1; break; } } if(tag==0) break; } } int main() { char data[] = "AAAAA.BBBBB"; f(data); return 0; }
机器人塔
X星球的机器人表演拉拉队有两种服装,A和B。
他们这次表演的是搭机器人塔。
类似:
A
B B
A B A
A A B B
B B B A B
A B A B B A
队内的组塔规则是:
A 只能站在 AA 或 BB 的肩上。
B 只能站在 AB 或 BA 的肩上。
你的任务是帮助拉拉队计算一下,在给定A与B的人数时,可以组成多少种花样的塔。
输入一行两个整数 M 和 N,空格分开(0<M,N<500),分别表示A、B的人数,保证人数合理性。
要求输出一个整数,表示可以产生的花样种数。
例如:
用户输入:
1 2
程序应该输出:
3
再例如:
用户输入:
3 3
程序应该输出:
4
资源约定:
峰值内存消耗 < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0
注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。
注意: 所有依赖的函数必须明确地在源文件中 #include <xxx>, 不能通过工程设置而省略常用头文件。
提交时,注意选择所期望的编译器类型。
//题目没有看清楚,思路错误的想到二叉树上面,所以下面是完全错误的答案
#include<algorithm> #include<iostream> #include<cstdio> #include<cmath> using namespace std; typedef long long LL; LL a[33][501][501],b[33][501][501]; int main(void) { a[1][1][0]=1,a[2][3][0]=1,a[2][1][2]=1; b[1][0][1]=1,b[2][1][2]=2; int M,N; cin >> M >> N; int x = (-1+(int)(sqrt(1.0+8*M+8*N)+0.5))/2; //cout <<"x="<<x<<endl; for(int k=3;k<=x;k++) for(int i=0;i<=k*(k+1)/2;i++) { int j=k*(k+1)/2-i; //计算 a[k][i][j] , b[k][i][j] if(i>=1) { //a[k][i][j] for(int m=1;m+1<=i-1;m++) a[k][i][j]+=a[k-1][m][k*(k-1)/2-m]*a[k-1][i-1-m][k*(k-1)/2-(i-1-m)]; for(int n=1;n+1<=j;n++) a[k][i][j]+=b[k-1][k*(k-1)/2-n][n]*b[k-1][k*(k-1)/2-(j-n)][j-n]; } if(j>=2) { for(int n=1;n<=j-1;n++) { b[k][i][j]+=2*a[k-1][k*(k-1)/2-(j-1-n)][j-1-n]*b[k-1][k*(k-1)/2-n][n]; /* if(i==3 && j==3) { printf("b[3][3][3] += 2* a[%d][%d][%d] * b[%d][%d][%d] = 2* %d * %d ",k-1,k*(k-1)/2-(j-1-n),j-1-n,k-1,k*(k-1)/2-n,n,a[k-1][k*(k-1)/2-(j-1-n)][j-1-n],b[k-1][k*(k-1)/2-n][n]); } */ } } } //for(int i=0;i<=6;i++) printf("a[3][%d][%d]=%d ",i,6-i,a[3][i][6-i]); //for(int i=0;i<=6;i++) printf("b[3][%d][%d]=%d ",i,6-i,b[3][i][6-i]); LL sum = a[x][M][N]+b[x][M][N]; cout << sum ; return 0; }
再给出一个暴力求解的方法:只能通过估计20%左右的数据估计。
位向量法:解答树的节点虽然多,但是速度挺快的,但是要求n是一个非常小的整数,但是这里的显然不可满足条件。
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int a[50],M,N,sum,x; void dfs(int cur) { if(cur==x) { int z=x,numa=0,numb=0; while(z) { for(int i=0;i<z;i++) if(a[i]) numa++; else numb++; z--; for(int i=0;i<z;i++) if(a[i]==a[i+1]) a[i]=1; else a[i]=0; } if(numa==M && numb==N) sum++; } else { a[cur]=1; dfs(cur+1); a[cur]=0; dfs(cur+1); } } int main(void) { cin >> M >> N; int i=1; while(i*(i+1)/2 != M+N) i++; x = i; dfs(0); cout << sum << endl; return 0; }
下面是一个示例:
#include<iostream> #include<algorithm> #include<cstdio> using namespace std; void print_subset(int n,int *b,int cur) { if(cur==n) { for(int i=0;i<cur;i++) printf("%d",b[i]); printf(" "); return ; } b[cur]=1; print_subset(n,b,cur+1); b[cur]=0; print_subset(n,b,cur+1); } int main(void) { int n; cin >> n; int b[100]; print_subset(n,b,0); return 0; } /* 输入5,结果如下: 5 11111 11110 11101 11100 11011 11010 11001 11000 10111 10110 10101 10100 10011 10010 10001 10000 01111 01110 01101 01100 01011 01010 01001 01000 00111 00110 00101 00100 00011 00010 00001 00000 */
然后再给出一个自己写的暴力破解的代码,这个代码是错误的,输出序列,发现序列是不正确的:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; int M,N,x,sum; int a[50]; void DFS(int cur,int numa,int numb) { if(cur==x) { //输出序列 for(int i=0;i<x;i++) printf("%d",a[i]); cout << endl; /* for(int i=x-1;i>=1;i--) { for(int j=0;j<i;j++) { if(a[j]==a[j+1]) { a[j]=1; numa++; } else { a[j]=0; numb++; } } } */ int z=x; numa=numb=0; for(int i=0;i<z;i++) if(a[i]) numa++; else numb++; //此时结果是正确的,说明递归的过程中,numa和numb计算出错了。 while(z) { for(int i=0;i+1<z;i++) if(a[i]==a[i+1]) a[i]=1,numa++; else a[i]=0,numb++; z--; } if(numa==M && numb==N) sum++; } else { a[cur]=1; DFS(cur+1,numa+1,numb); a[cur]=0; DFS(cur+1,numa,numb+1); } } int main(void) { cin >> M >> N; x = (-1+(int)(sqrt(1.0+8*M+8*N)+0.5))/2; DFS(0,0,0); cout << sum << endl; return 0; } /* 3 3 111 110 001 000 011 010 101 100 4 */
找了半天都没有找出来哪里出了问题,后来发现再最后修改a数组的时候,修改了不能修改的数据,这时候正常的做法是使用一个新的数组记录a的值,然后再计算。
这个时候估计也可以想到,第一个方法也是有问题的,但是恰好数据通过,没有注意到这个问题。然后再重新写一个代码:
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int b[100],M,N,sum,x; void dfs(int cur) { if(cur==x) { int a[100]; for(int i=0;i<x;i++) cout << b[i]; cout << endl; int z=x,numa=0,numb=0; for(int i=0;i<x;i++) a[i]=b[i]; while(z) { for(int i=0;i<z;i++) if(a[i]) numa++; else numb++; z--; for(int i=0;i<z;i++) if(a[i]==a[i+1]) a[i]=1; else a[i]=0; } if(numa==M && numb==N) sum++; } else { b[cur]=1; dfs(cur+1); b[cur]=0; dfs(cur+1); } } int main(void) { cin >> M >> N; int i=1; while(i*(i+1)/2 != M+N) i++; x = i; dfs(0); cout << sum << endl; return 0; }
这样就是一个可以正常运行计算出部分答案的程序了。