您的位置:首页 > 其它

poj 3276 反转开关问题(一) DP+模拟

2014-03-04 00:40 357 查看


http://poj.org/problem?id=3276

题意:n头牛,F表示朝前,B表示朝后,每次可以让连续的k头牛变换方向,要使所有的牛都朝前,求最小的转向次数及此时的k

Sample Input

7
B
B
F
B
F
B
B


Sample Output
3 3


穷举肯定是要超时的 2^n个状态...但是先思考一些规律吧:

1、转动奇数次,必然与初始方向相反;

2、转动偶数次,必然与初始方向相同;

枚举k:1-n,得到O(n^3)的代码:(这个代码会超时,只是模拟而已)

//TLE O(n^3)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
#define MAXN 5005

int s[MAXN];
int n;

int test(int k)
{
int i,j,ans=0;

for(i=0;i<n-k+1;i++)
{
if(!s[i])
{
for(j=i;j<i+k;j++)
{
s[j]=!s[j];
}
ans++;
}
}
for(j=i;j<n;j++)
if(!s[j])
return -1;
return ans;
}

int main()
{
int i,len,kmin,m,mmin,k;
char cow[MAXN];

while(scanf("%d",&n)!=EOF)
{
memset(s,0,sizeof(s));
mmin = MAXN;
m=-1;

for(i=0;i<n;i++)
{
scanf("%c",&cow[i]);
if(cow[i]=='\n')
i--;
}
cow[i]='\0';

for(k=1;k<=n;k++)
{
for(i=0;i<n;i++)
{
if(cow[i] == 'F')
s[i]=1;
else
s[i]=0;

}
m=test(k);
///////////////
//printf("m=%d\n",m);
///////////////
if(m>=0&&m<mmin)
{
kmin=k;
mmin=m;
}
}

printf("%d %d\n",kmin,mmin);
}

return 0;
}


再做处理是可以降低时间复杂度的
f[i]  表示从i-k+1到i头牛的反转情况,值为1表示反转,值为0表示没有反转

那么sum=f[i-k+1]+f[i-k+2]+...+f[i-1],如果sum为基数,那么转动奇数次,必然与初始方向相反,如果sum为偶数,必然与初始方向相同。

于是省去一重循环,得到O(n^2)的代码  AC

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

using namespace std;
#define MAXN 5005

int s[MAXN];
int f[MAXN];
int n;

int test(int k)
{
int i,j,ans=0,sum=0;

memset(f,0,sizeof(f));
for(i=0;i<n-k+1;i++)
{
if((sum)%2 == 1)
{
if(s[i])
{
ans++;
f[i]=1;
}

}
else
{
if(!s[i])
{
ans++;
f[i]=1;
}
}
sum+=f[i];
if(i-k+1>=0)
sum-=f[i-k+1];
}
for(i=n-k+1;i<n;i++)
{
if(sum%2)
{
if(s[i])
return -1;
}
else
{
if(!s[i])
return -1;
}
if(i-k+1>=0)
sum-=f[i-k+1];
}
//if(!s[i])
// return -1;

return ans;
}

int main()
{
int i,len,kmin,m,mmin,k;
char cow[MAXN];

while(scanf("%d",&n)!=EOF)
{

memset(s,0,sizeof(s));
mmin = MAXN;
m=-1;

for(i=0;i<n;i++)
{
scanf("%c",&cow[i]);
if(cow[i]=='\n')
{
i--;
continue;
}

if(cow[i] == 'F')
s[i]=1;
else
s[i]=0;
}
cow[i]='\0';

for(k=1;k<=n;k++)
{

m=test(k);
if(m>=0&&m<mmin)
{
kmin=k;
mmin=m;
}
}

printf("%d %d\n",kmin,mmin);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: