- /*******************************************************************************
- 76. (省刻度尺问题)给定长度为 L 的直尺, L 为整数, 且L≤40. 为了能一次直接
- 量出 1,2,...,L 的各种长度, 该尺内部至少要有多少条刻度 ? 请输出最少刻度
- 数( 不含两端点)及每个刻度的位置. 测量长度时可利用两端点, 其位置分别为 0,
- L.
- 输入: 由键盘输入 L.
- 输出: 用文本文件按以下格式输出结果(文件名: ANS2.TXT):
- 第 1 行: S ( 最少刻度数 )
- 第 2 行: 尺内 S 个刻度的位置
- 第 3 行至第 L+2 行: 每行输出 3 个用空格隔开的整数 t m n, 其中
- 1≤t≤L 为要测量的各长度, m,n 依次为该长度的起止刻度 (m<n).
- 例: 如果 L=6, 则一个正确的输出是:
- 2
- 1 4 提示: (1) 最少刻度数 S 应满足:
- 1 0 1 C[S+2,2]=(S+2)*(S+1)/2≥L.
- 2 4 6 (2) 除两端点外, 第一个刻度可取为
- 3 1 4 A[1]=1, 第二个刻度可在 1, L-2, L-1 这
- 4 0 4 三个数中选取.
- 5 1 6
- 6 0 6
- *****************************************************************************/
- /*检验程序
- #include <stdio.h>
- #include <stdlib.h>
- #define N 46
- #define M 12
- int kd[M];
- int checked(int kd[])
- {
- int i,j;
- int ch[N];
- for(i=0; i<N; i++)
- ch[i] = 0;
- for(i=0; i<M-1; i++)
- for(j=i+1; j<M; j++)
- {
- ch[kd[j]-kd[i]-1] = 1;
- }
- for(i=0; i<N; i++)
- {
- if(!ch[i])
- return 0;
- }
- return 1;
- }
- void comb(int a[], int n, int r)
- {
- if(r==0)
- {
- int i;
- for(i=2; i<M-1; i++)
- kd[i] = a[i-2]+1;
- if(checked(kd))
- {
- for(i=0; i<M; i++)
- {
- printf("%d ",kd[i]);
- }
- printf("/n");
- _exit(-1);
- }
- }
- else if(n>=r)
- {
- a[r-1] = n;
- comb(a,n-1,r-1);
- comb(a,n-1,r);
- }
- }
- void main()
- {
- int a[M-3];
- kd[0] = 0;
- kd[1] = 1;
- kd[M-1] = N;
- comb(a,N-2,M-3);
- }
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <malloc.h>
- typedef struct
- {
- int s;
- int t;
- } ST;
- int M;
- int L;
- int *kd;
- int *chk;
- int *comb;
- ST *st;
- //检验合法性
- int checked()
- {
- int i,j;
- //组合转化为刻度
- for(i=2; i<M-2; i++)
- kd[i] = comb[i-2]+2;
- //检查数组初时化为0,检测该刻度是否能表示
- for(i=0; i<L; i++)
- chk[i] = 0;
- for(i=0; i<M-1; i++)
- {
- for(j=i+1; j<M; j++)
- {
- chk[kd[j]-kd[i]-1] = 1;
- }
- }
- //判断刻度是否能表示,如果有一个不能表示,返回不合法
- for(i=0; i<L; i++)
- {
- if(!chk[i])
- {
- return 0;
- }
- }
- //合法
- //保存表示值
- for(i=0; i<M-1; i++)
- {
- for(j=i+1; j<M; j++)
- {
- st[kd[j]-kd[i]-1].s = kd[i];
- st[kd[j]-kd[i]-1].t = kd[j];
- }
- }
- //返回合法
- return 1;
- }
- //生成第一个组合
- int FirstComb(int r)
- {
- int i;
- if(r == 0)
- return 0;
- for(i=0; i<r; i++)
- comb[i] = i;
- return 1;
- }
- //生成下一组合
- int NextComb(int n, int r)
- {
- int i,j;
- i = r - 1;
- while (comb[i] == n - r + i)
- {
- i--;
- }
- if(i<0) return 0;
- comb[i] = comb[i] + 1;
- for (j = i + 1; j < r; j++)
- {
- comb[j] = comb[i] + j - i;
- }
- return 1;
- }
- //显示结果
- void PrintRs()
- {
- int i;
- printf("%d/n",M-2);
- for(i=1; i<M-1; i++)
- printf("%d ",kd[i]);
- printf("/n");
- for(i=0; i<L; i++)
- {
- printf("%2d %3d %3d/n",i+1,st[i].s,st[i].t);
- }
- printf("/n");
- }
- //main函数
- void main()
- {
- printf("请输入刻度尺的量程L:");
- scanf("%d",&L);
- //求出最小刻度数
- for(M=2; (M-1)*M<2*L; M++);
- //检验数组
- chk = (int*)malloc(L*sizeof(int));
- //刻度表示值数组
- st = (ST*)malloc(L*sizeof(ST));
- L1: //刻度值数组
- kd = (int*)malloc(M*sizeof(int));
- kd[0] = 0;
- kd[M-1] = L;
- if(M == 2)
- {
- if(checked())
- {
- PrintRs();
- goto L3;
- }
- goto L2;
- }
- else if(M == 3)
- {
- kd[1] = 1;
- if(checked())
- {
- PrintRs();
- goto L3;
- }
- goto L2;
- }
- else if(M == 4)
- {
- kd[1] = 1;
- kd[M-2] = L-1;
- if(checked())
- {
- PrintRs();
- goto L3;
- }
- kd[M-2] = L-2;
- if(checked())
- {
- PrintRs();
- goto L3;
- }
- goto L2;
- }
- else if(M > 4)
- {
- kd[1] = 1;
- kd[M-2] = L-1;
- comb = (int*)malloc((M-4)*sizeof(int));
- if(FirstComb(M-4))
- {
- do
- {
- if(checked())
- {
- PrintRs();
- goto L3;
- }
- }while(NextComb(L-3, M-4));
- }
- kd[M-2] = L-2;
- if(FirstComb(M-4))
- {
- do
- {
- if(checked())
- {
- PrintRs();
- goto L3;
- }
- }while(NextComb(L-4, M-4));
- }
- goto L2;
- }
- L2:
- free(kd);
- free(comb);
- M++;
- goto L1;
- L3:
- free(kd);
- free(comb);
- free(st);
- free(chk);
- }
练习76
最新推荐文章于 2022-09-02 12:26:14 发布