floj2678

题目链接

题意:

给出一个由(n-1)("A")(n-1)("B")和两个连续的空位置(用(".")表示)构成的长(2*n)的字符串(N<=100)
现在可以进行不超过1000次的操作使得任意字符A前没有字符B
每次操作如下:选择两个连续的字符,将他们放到空的两个位置上
输出最小修改次数及方案

题解:

考虑对序列进行操作后最左侧为A,最右侧为B,这样解决子问题就行了
可以发现只要序列长度大于4,总可以进行以上操作
那么对于序列长度=4时,分类讨论即可
若此时已经满足条件,完成
否则,若序列原长度为4,则无解
若原长=6

ABA..B →→ ..AABB
A..BAB →→ AABB..
AB..AB →→无解

若原长>=8,原来无解的情况也有解

AAB..ABB →→ ..BAAABB→→ AABA..BB →→ A..AABBB

code:

#include<bits/stdc++.h>
using namespace std;
int n,pos;
bool flag;
string s;
vector<string>ans;
inline void update(int x)
{
	swap(s[x],s[pos]);swap(s[x+1],s[pos+1]);
	ans.push_back(s);
	pos=x;
}
inline void work(int l,int r)
{
	if(r-l+1>4)
	{
		if(s[l]!='A')
		{
			if(pos==l+1)update(l+3);
			if(pos!=l)update(l);
			for(int i=l+2;i<r;++i)
				if(s[i]=='A'){update(i);break;}
		}
		if(s[r]!='B')
		{
			if(pos==r-2)update(r-4);
			if(pos!=r-1)update(r-1);
			for(int i=r-2;i>l;--i)
				if(s[i]=='B'){update(i-1);break;}
		}
		work(l+1,r-1);
	}
	else
	{
		for(int i=l;i<=r;++i)
		{
			if(s[i]=='A')return;
			if(s[i]=='B')break;
		}
		if(n==2){flag=1;return;}
		if(s[l]=='B'&&s[l+1]=='A'){update(l-1);return;}
		if(s[r]=='A'&&s[r-1]=='B'){update(r);return;}
		if(n==3)flag=1;
		else update(l-2),update(r-1),update(l-1);
		return;
	}
}
int main()
{
	scanf("%d",&n);
	if(n==1)return puts("0"),0;
	cin>>s;
	for(int i=0;i<2*n;++i)
		if(s[i]=='.'){pos=i;break;}
	work(0,2*n-1);
	if(flag)puts("-1");
	else
	{
		printf("%d
",ans.size());
		for(size_t i=0;i<ans.size();++i)
			cout<<ans[i]<<endl;
	}
	return 0;
}
原文地址:https://www.cnblogs.com/zmyzmy/p/13631920.html