AcWing 137. 雪花雪花雪花(字符串的最小表示法)

该博客介绍了一种算法,用于检查给定的多个雪花形状是否重复。雪花由六个边长组成,形状相同意味着六个边长的序列在顺时针或逆时针旋转后相同。程序首先计算每个雪花及其翻转的最小表示,然后通过比较找到是否有两个雪花的最小表示相同。如果找到,输出'Twinsnowflakesfound.',否则输出'Notwosnowflakesarealike.'。
摘要由CSDN通过智能技术生成

题目描述

有N片雪花,每片雪花由六个角组成,每个角都有长度。
第i片雪花六个角的长度从某个角开始顺时针依次记为ai,1,ai,2,…,ai,6。
因为雪花的形状是封闭的环形,所以从任何一个角开始顺时针或逆时针往后记录长度,得到的六元组都代表形状相同的雪花。
例如ai,1,ai,2,…,ai,6和ai,2,ai,3,…,ai,6,ai,1就是形状相同的雪花。
ai,1,ai,2,…,ai,6和ai,6,ai,5,…,ai,1也是形状相同的雪花。
我们称两片雪花形状相同,当且仅当它们各自从某一角开始顺时针或逆时针记录长度,能得到两个相同的六元组。
求这N片雪花中是否存在两片形状相同的雪花。
输入格式
第一行输入一个整数N,代表雪花的数量。
接下来N行,每行描述一片雪花。
每行包含6个整数,分别代表雪花的六个角的长度(这六个数即为从雪花的随机一个角顺时针或逆时针记录长度得到)。
同行数值之间,用空格隔开。
输出格式
如果不存在两片形状相同的雪花,则输出:
No two snowflakes are alike.
如果存在两片形状相同的雪花,则输出:
Twin snowflakes found.
数据范围
1≤n≤100000,
0≤ai,j<10000000
输入样例:
2
1 2 3 4 5 6
4 3 2 1 6 5
输出样例:
Twin snowflakes found.

题解

  1. 一个字符串通过旋转可以得到多个不同的字符串。可以用一个字典序最小的字符串来表示这些字符串。即字符串的最小表示可以表示一类字符串。
  2. 可以求出每个字符串以及翻转后的字符串的最小表示的最小值。判断最小表示有没有相同的字符串。

代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 100010;
int n;
int snows[N][6]; //存储每个字符串的最小表示
int idx[N];

//两个字符串比较
bool cmp_array(int a[], int b[])
{
    for(int i = 0; i < 6; i++)
    {
        if(a[i] > b[i]) return false;
        else if(a[i] < b[i]) return true;
    }
    
    return false;
}

//sort排序函数
bool cmp(int a, int b)
{
    return cmp_array(snows[a], snows[b]);
}

//字符串最小表示模板
void get_min(int a[])
{
    static int b[12];
    for(int i = 0; i < 12; i++) b[i] =  a[i % 6];
    
    int i = 0, j = 1, k;
    while(i < 6 && j < 6)
    {
        for(k = 0; k < 6 && b[i + k] == b[j + k]; k++);
        if(k == 6) break;
        if(b[i + k] > b[j + k])
        {
            i += k + 1;
            if(i == j) i++;
        }
        else
        {
            j += k + 1;
            if(i == j) j++;
        }
    
    }
    
    k = min(i, j);
    
    for(int i = 0; i < 6; i++) a[i] = b[i + k];
    
}

int main()
{
    scanf("%d", &n);
    int snow[6], isnow[6];
    for(int i = 0; i < n; i++)
    {
        for(int j = 0, k = 5; j < 6; j++, k--)
        {
            scanf("%d", &snow[j]);
            isnow[k] = snow[j];
        }
        
        get_min(snow);
        get_min(isnow);
        
        if(cmp_array(snow, isnow)) memcpy(snows[i], snow, sizeof snow);
        else memcpy(snows[i], isnow, sizeof isnow);
        idx[i] = i;
    }
    
    //排索引
    sort(idx, idx + n, cmp);
    
    bool flag = false;
    
    for(int i = 1; i < n; i++)
    {
    	//判断两个字符串是否相等
        if(!cmp(idx[i - 1], idx[i]) && !cmp(idx[i], idx[i - 1]))
        {
            flag = true;
            break;
        }
    }
    
    if(flag) puts("Twin snowflakes found.");
    else puts("No two snowflakes are alike.");
        
   return 0; 
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值