2532 前缀和后缀 (字符串子串判断——复杂的正向模拟该怎么简化?)

2532 前缀和后缀

小b有一个长度为2n-2的只含小写字母的字符串S,她求出了S的长度分别为1...n−1n−1个前

缀和长度分别为1...n−1n−1个后缀。

现在她告诉你这2n-2个字符串(并不告诉你哪些是前缀哪些是后缀),但她可能说谎,即改变

某些字符串的某些字符(注意不可能改变长度)。

请问小b说的有没有可能是真的?即是否存在串S使得小b给出的串能和串S的长度为1...n−1

前后缀一一对应。

输入

第一行一个正整数n,2<=n<=100。
接下来2n-2行,每行一个字符串。

输出

如果小b说的可能是真的,输出"Possible";
否则输出"Impossible"。

输入样例

2
a
c

输出样例

Possible

题意:

         最后一句话是题意。

思路:

        PS:题目其实是保证长度合法的,所以不需要特殊判断。

        自己的思路是排序后看第一个字符串属于前缀还是后缀,然后按顺序分情况讨论下去,

100多行。。。,其实我是在很暴力的正向模拟整个过程,缺点是每次匹配完后,参与匹配

的两个串都将发生变化,模拟过程巨复杂。

       更好的思路是将两个最长的串拼接(两种方式,分别作为前缀和后缀),即逆向考虑,

然后遍历所有的其他字串(两两一组),看是不是能和最长串发生匹配。这样只需要固定

两个拼接好的串然后遍历判断其他串即可,过程简化了许多。

第二种思路题解的代码:

#include <bits/stdc++.h>
using namespace std;
const int maxN = 200;
struct ch {
	int a;
	string b;
};
int n;
ch ss[maxN + 5];
string c;
bool cmp(ch A, ch B) {
	return A.a < B.a;
}
string s1, s2;
int m;
bool checkpre(string x,string y) {
	for(int i=0; i<y.size(); i++)
		if(x[i]!=y[i]) return 0;
	return 1;
}
bool checksuf(string x,string y) {
	int ptr = y.size()-1;
	for(int i=x.size()-1; i>=x.size()-y.size(); i--)
		if(x[i]!=y[ptr--]) return 0;
	return 1;
}
bool check(string x) {
	for(int i = 0; i < m ; i += 2) {
		if(checkpre(x,ss[i].b)&&checksuf(x,ss[i+1].b)) continue;
		if(checksuf(x,ss[i].b)&&checkpre(x,ss[i+1].b)) continue;
		return 0;
	}
	return true;
}
int main () {
	cin >> n;
	m = 2 * n - 2;
	for(int i = 0; i < m; i++) {
		cin >> c;
		ss[i].b = c;
		ss[i].a = c.length();
	}
	sort(ss,ss + m,cmp);
	s1 = ss[m - 1].b + ss[m - 2].b;
	s2 = ss[m - 2].b + ss[m - 1].b;
	if(!check(s1)) {
		if(!check(s2)) cout << "Impossible" << endl;
		else cout << "Possible" << endl;
	} else cout << "Possible" << endl;
	return 0;
}

第一思路:自己的巨复杂的模拟+无数分支判断:

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<math.h>
#include<set>
#include<algorithm>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=2e5+100;
const int M=4e5+100;
string str[N];
bool cmp(string aa,string bb)
{
    return aa.length()<bb.length();
}
int vis[N];
int main()
{
    int n,flag=0;
    cin>>n;
    for(int i=1; i<=2*n-2; i++)
    {
        cin>>str[i];
    }
    sort(str+1,str+n*2-1,cmp);
    int cnt=1;
    for(int  i=1; i<=2*n-2; i+=2)
    {
        if(str[i].length()==str[i+1].length()&&str[i].length()==cnt++)
        {
            continue;
        }
        else
        {
            cout<<"Impossible"<<endl;
            return 0;
        }
    }
    if(n==2)
    {
        cout<<"Possible"<<endl;
        return 0;
    }
    //2*n-2>=4
//	for(int i=1;i<=2*n-2;i++){
//		cout<<i<<":"<<str[i]<<"..."<<endl;
//	}
    if(str[1]+str[3][1]==str[3])
    {
        vis[3]=1;
        vis[1]=1;
        cnt=3;
        int p=3;
        for(int i=3; i<=2*n-4; i+=2)
        {
            if(str[p]+str[i+3][cnt-1]==str[i+3])
            {
                vis[i+3]=1;
                p=i+3;
            }
            else if(str[p]+str[i+2][cnt-1]==str[i+2])
            {
                vis[i+2]=1;
                p=i+2;
            }
            else
            {
                //cout<<i<<":"<<str[i]<<" "<<str[i+2]<<" "<<str[i+3]<<endl;
                cout<<"Impossible"<<endl;
                return 0;
            }
            cnt++;
        }
    }
    else if(str[1]+str[4][1]==str[4])
    {
        cnt=3;
        vis[4]=1;
        vis[1]=1;
        int p=4;
        for(int i=4; i<=2*n-4; i+=2)
        {
            if(str[p]+str[i+1][cnt-1]==str[i+1])
            {
                vis[i+1]=1;
                p=i+1;
            }
            else if(str[p]+str[i+2][cnt-1]==str[i+2])
            {
                vis[i+2]=1;
                p=i+2;
            }
            else
            {
                cout<<"Impossible"<<endl;
                return 0;
            }
            cnt++;
        }

    }
    else if(str[3][0]+str[1]==str[3])
    {
        vis[3]=2;
        vis[1]=2;
        int p=3;
        for(int i=3; i<=2*n-4; i+=2)
        {
            if(str[i+3][0]+str[p]==str[i+3])
            {
                vis[i+3]=2;
                p=i+3;
            }
            else if(str[i+2][0]+str[p]==str[i+2])
            {
                vis[i+2]=2;
                p=i+2;
            }
            else
            {
                cout<<"Impossible"<<endl;
                return 0;
            }
        }
    }
    else if(str[4][0]+str[1]==str[4])
    {
        vis[4]=2;
        vis[1]=2;
        int p=4;
        for(int i=4; i<=2*n-4; i+=2)
        {
            if(str[i+1][0]+str[p]==str[i+1])
            {
                vis[i+1]=2;
                p=i+1;
            }
            else if(str[i+2][0]+str[p]==str[i+2])
            {
                vis[i+2]=2;
                p=i+2;
            }
            else
            {
                cout<<"Impossible"<<endl;
                return 0;
            }
        }
    }
    else
    {
        cout<<"Impossible"<<endl;
        return 0;
    }

    string s=str[2];
    if(vis[1]==1)
    {
        for(int i=3; i<=2*n-2; i++)
        {
            if(vis[i]==0)
            {
                if(str[i][0]+s==str[i])s=str[i];
                else
                {
                    cout<<"Impossible"<<endl;
                    return 0;
                }
            }
        }
    }
    else
    {
        cnt=2;
        for(int i=3; i<=2*n-2; i++)
        {
            if(vis[i]==0)
            {
                if(s+str[i][cnt-1]==str[i])s=str[i];
                else
                {
                    cout<<"Impossible"<<endl;
                    return 0;
                }
                cnt++;
            }
        }
    }

    cout<<"Possible"<<endl;
    return 0;

}

THE END;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值