首页 > 试题广场 >

小红的排列构造②

[编程题]小红的排列构造②
  • 热度指数:4103 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}小红定义一个仅由 \texttt{0}\texttt{1} 两个字符构成的字符串 s 与一个长度为 n 的数组 p匹配,当且仅当满足下列两点:
{\hspace{20pt}}_\texttt{1.}\,s_i=\texttt{1},则数组 \{p_1,p_2,\dots,p_i\} 恰好构成一个排列;
{\hspace{20pt}}_\texttt{2.}\,s_i=\texttt{0},则数组 \{p_1,p_2,\dots,p_i\} 无法构成一个排列。

\hspace{15pt}现在小红给出了一个长度为 n 的字符串 s,请你构造一个长度为 n 的排列 p 使得 sp 匹配;如果不存在这样的排列,请输出 -1

\hspace{15pt}【名词解释】
\hspace{23pt}\bullet\,排列排列是由 1\sim nn 个整数按任意顺序组成的数组,其中每个整数恰好出现一次。

输入描述:
\hspace{15pt}第一行输入一个整数 n\left(1\leqq n\leqq 10^5\right) 表示字符串及排列的长度。 
\hspace{15pt}第二行输入一个长度为 n,仅由 \texttt{0}\texttt{1} 构成的字符串 s


输出描述:
\hspace{15pt}如果不存在满足条件的排列,直接输出 -1;否则,在一行上输出 n 个整数 p_1,p_2,\dots,p_n 表示你构造出的排列。 
\hspace{15pt}如果存在多个满足条件的排列,输出任意一个均可,系统将自动判定其正确性。请注意,自测运行功能可能因此返回错误结果,请自行检查答案正确性。
示例1

输入

3
001

输出

3 1 2

说明

\hspace{15pt}对于这个样例,
\hspace{23pt}\bullet\,由于 s_0 = {\tt 0},排列的前一项元素无法构成一个排列;
\hspace{23pt}\bullet\,由于 s_1 = {\tt 0},排列的前两项元素无法构成一个排列;
\hspace{23pt}\bullet\,由于 s_2 = {\tt 1},排列的前三项元素构成一个排列;
\hspace{15pt}同时,输出 \{2,3,1\}\{3,2,1\} 等答案也都是合法的。
示例2

输入

4
1110

输出

-1

说明

在此样例中,若存在合法排列,则前三位必须依次形成排列,但第四位又要求整体不形成排列,显然不可能,因此答案为 -1
卧槽,自己想的算法,没看评论区,居然一次性通过所有用例,我运气真好
总体思路:先把数组 p按递增序列初始化,然后对比字符串s,遇到s[i]=1,则p[i]的值保持不变。遇到s[i]=0,则找下一个s[b]=1的位置的p[b]和当前p[i]交换数值,如果找不到s[b]=1的位置等于1,则表示无解。
#include <stdio.h>
#include <stdlib.h>
//让我判断是不是匹配还好说,让我构造??
//只能找规律,再想五分钟想不出来就老实看答案。
//好像找到规律了,遇到1则填对应的数字即可,遇到0则和下一个是1的位置交换数字即可,交换完之后就跳过下一个1的位置,不过这种只适合有解的情况啊。如果后面找不到有1的情况,则就当无解把
int main() {
    int n;
    
    scanf("%d",&n);

    char *string=malloc(sizeof(char)*(n+1));
    scanf("%s",string);

    //去掉字符串的0位置,然后末尾的'\0'也不要了,这样结果才能一一对应
    for(int i=n;i>0;i--)
    {
        string[i]=string[i-1];
    }

    int *result=malloc(sizeof(int)*(n+1));
    for(int i=0;i<=n;i++) //初始结果数组为递增数组,但是后面元素下标为0的数字不用
    {
        result[i]=i;
    }

    //然后和字符串一一对应的了,找能交换的位置了
    for (int i=1; i<=n; ) {
        if(string[i]=='1')  //遇到1则结果数组保持原样
        {
            i++;
        }else if(string[i]=='0')         //遇到0则找下一个为1的位置交换
        {
            int a=i;//记录当前位置
            while(string[i]=='0')  //跳过所有0的位置
            {
                i++;
                if (i>n) {  //如果找完后续所有位置都没有1的位置,则无解
                    printf("-1");
                    return 0;
                }
            }
            //来到了string[i]=='1'的位置,和a的职位交换
            int temp=result[a];
            result[a]=result[i];
            result[i]=temp;    //交换
            i++; //移动到下一个位置继续探索
        }
    }

    //输出result数组的所有结果
    for(int i=1; i<=n; i++)
    {
        printf("%d ",result[i]);
    }
    
    return 0;
}


发表于 2025-10-18 15:14:14 回复(0)