《编程思维与实践》1038.排版
题目
思路
分两个步骤进行解决:
1.在给定长度下找到每一行可以容纳的最多单词数(单词长度<M/2保证每行至少有两个单词);
2.输出时补充额外的空格.
其中,第一个步骤可以通过分割字符串将每个字符串存起来,再找到第一个超过给定长度M的单词来实现.
主要考虑第二个步骤:
要满足两个条件,空格的分布尽可能平均,同时空格尽可能靠右.
如:8个空格分在3个位置则每个位置空格数为2 3 3.
以8为例: 原先保证至少有一个空格 记为1 1 1 ,需要额外填充5个空格,5/3取整为1,也就是平均每个还需要补充1个空格,
则1 1 1 -> 2 2 2 ,还需要填充2个空格,这时只能填充在后两个位置上(靠右原则),2/2=1, 所以最后2 2 2-> 2 3 3.
注意的点:
1.第一个步骤中统计长度时需要包含两个单词之间本身的空格(统计每个单词时算上前置的空格即可).
2.对最后一行的输出需要进行判定,正常输出包含本身的空格即可.
3.最后一个单词后面没有空格.
代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
int main()
{
int T;
scanf("%d",&T);
for(int i=0;i<T;i++)
{
int M;
scanf("%d",&M);
getchar(); //读回车 或者直接scanf("%d\n",&M)
char s[2001];
gets(s);
printf("case #%d:\n",i);
int count=0; //统计给的数据有多少个字符串
for(int j=0;j<strlen(s);j++)
{
if((s[j]!=' '&&s[j+1]==' ')||(s[j]!=' '&&s[j+1]=='\0')) //通过空格来计数
{
count++;
}
}
char str[count][100]; //将每个字符串存起来
int k=0;
for(int j=0;j<strlen(s);j++)
{
int m=0;
while(isspace(s[j]))
{
j++;
}
while(j<strlen(s)&&!isspace(s[j])) //防止越界(条件放前)
{
str[k][m++]=s[j++];
}
str[k++][m]='\0';
}
int len=0; //存每行中含有元素个数(含两者之间的空格)
int num=0; //计算每行的字符串个数
for(int j=0;j<count;j++)
{
len+=len==0?strlen(str[j]):strlen(str[j])+1; //第一个单词前没空格
num++;
if(len>M||j==count-1) //可以输出的情况,同时找到第一个超过给定长度M的单词
{
if(len>M) //求一行中可以输出的最多单词数
{
len-=strlen(str[j])+1;
num--;
j--;
}
if(j!=count-1) //不是最后一行输出
{
int space_num=M-len; //需要额外输出的空格数
int space=space_num/(num-1); //平均数 至少有两个单词保证num≠1
int temp=space; //需要输出的空格数 (如2 2 2->2 3 3需要存3)
for(int k=j+1-num;k<=j;k++)
{
printf("%s",str[k]);
if(k!=j) //最后一个单词后面没空格
{
printf(" ");
}
for(int p=0;p<temp;p++)
{
printf(" ");
}
space_num-=space*(num-1); //更新需要额外输出空格数
num--;
if(num!=1)
{
space=space_num/(num-1); //更新平均数
temp+=space; //上一位的空格数+平均数
}
}
printf("\n");
len=0; //重置len和num
num=0;
}
else //最后一行输出
{
for(int k=j+1-num;k<=j;k++)
{
printf("%s",str[k]);
if(k!=j)
{
printf(" ");
}
}
printf("\n");
}
}
}
}
return 0;
}