题目大致意思,一个由'*'和'.'组成的长度为N的字符串,现在有a个A和b个B去顶替其中的'.',不能有两个A相邻或B相邻的情况,问最后一共可以放几个A和B。
Example:
input
Copy
5 1 1 *...*
output
Copy
2
上手开始暴力求解......(这一段没有算法思想而且冗长,觉得没有意义就跳过吧)
#include<stdio.h>
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int n,best=0;
void solve(int a,int b,int index,int sum,string s)
{
if(index!=0&&index+1!=n)
{
if(s[index]=='.')
{
if(!a&&!b) best=max(best,sum);
if(s[index-1]!='A'&&a)
{
s[index]='A';
//cout<<s<<endl;
solve(a-1,b,index+1,sum+1,s);
s[index]='.';
}
if(s[index-1]!='B'&&b)
{
s[index]='B';
//cout<<s<<endl;
solve(a,b-1,index+1,sum+1,s);
s[index]='.';
}
}
else
solve(a,b,index+1,sum,s);
}
else if(n==1)
{
best=1;
}
else if(index==0)
{
if(s[index]=='.')
{
if(a)
{
s[index]='A';
//cout<<s<<endl;
solve(a-1,b,index+1,sum+1,s);
s[index]='.';
}
if(b)
{
s[index]='B';
//cout<<s<<endl;
solve(a,b-1,index+1,sum+1,s);
s[index]='.';
}
}
else
solve(a,b,index+1,sum,s);
}
else if(index==n-1)
{
if(s[index]=='.')
{
if(a==0&&b==0)
{
best=max(sum,best);
}
if(s[index-1]!='A'&&a)
best=max(sum+1,best);
if(s[index-1]!='B'&&b)
best=max(sum+1,best);
}
else
best=max(sum,best);
}
}
int main()
{
int a,b;
while(scanf("%d%d%d",&n,&a,&b)!=EOF)
{
char s[500];
scanf("%s",s);
best=0;
solve(a,b,0,0,s);
cout<<best<<endl;
}
return 0;
}
结果自然是超时。于是开始更换思想。
后来发现,其实每次去比较a和b是可行的,在一串连续的'*'中能坐下的最多的方式就是ABAB这样轮流坐,如果'*'数量是奇数,则在两端坐a和b中数量多的那个;如果是偶数,就只管往下安排就好了,a和b的差不会变。算是一种贪心策略吧。
#include<stdio.h>
#include<iostream>
#include<string>
using namespace std;
const int maxn = 2e5+5;
int main()
{
char seat[maxn];
int n,a,b,sum;
while(scanf("%d%d%d",&n,&a,&b)!=EOF)
{
getchar();
sum=a+b;
int flag;
for(int i=0;i<n;i++)
{
scanf("%c",&seat[i]);
if(seat[i]=='.'&&(a||b))
{
if(i==0||seat[i-1]=='*') //new start
{
if(a>b)
{
a--;
flag=1;
}
else
{
b--;
flag=0;
}
}
else
{
if(flag&&b)
{
b--;
flag=0;
}
else if(!flag&&a)
{
a--;
flag=1;
}
}
}
}
cout<<sum-a-b<<endl;
}
return 0;
}