POJ 3276 Face The Right Way

Face The Right Way

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 2665   Accepted: 1233

Description

Farmer John has arranged his N (1 ≤ N ≤ 5,000) cows in a row and many of them are facing forward, like good cows. Some of them are facing backward, though, and he needs them all to face forward to make his life perfect.

Fortunately, FJ recently bought an automatic cow turning machine. Since he purchased the discount model, it must be irrevocably preset to turn K (1 ≤ K ≤ N) cows at once, and it can only turn cows that are all standing
next to each other in line. Each time the machine is used, it reverses the facing direction of a contiguous group of K cows in the line (one cannot use it on fewer than K cows, e.g., at the either end of the line of cows). Each cow remains
in the same *location* as before, but ends up facing the *opposite direction*. A cow that starts out facing forward will be turned backward by the machine and vice-versa.

Because FJ must pick a single, never-changing value of K, please help him determine the minimum value of K that minimizes the number of operations required by the machine to make all the cows face forward. Also determine M, the
minimum number of machine operations required to get all the cows facing forward using that value of K.

Input

Line 1: A single integer: N

Lines 2..N+1: Line i+1 contains a single character, F or B, indicating whether cow i is facing forward or backward.

Output

Line 1: Two space-separated integers: K and M

Sample Input

7
B
B
F
B
F
B
B

Sample Output

3 3

Hint

For K = 3, the machine must be operated three times: turn cows (1,2,3), (3,4,5), and finally (5,6,7)

算法分析:

大概题意就是有n头牛,在一条直线上,有着不同的方向,前和后,现在让你寻找一个k值,使得每次都只能反转k头牛,求解最少次数与最小k。

当第一次看这个问题时,觉得还是有点棘手的,因为想改变一头牛的方向就必定影响k头牛,但在思考一下,当一头牛被反转2的倍数次时,与初始方向相同,可视为无反转,因为要枚举k并进行N-K+1(最坏情况)次反转,且每次翻转要不断改变dir(方向数组)数组的值,所以复杂度O(N^3),超时,但对于反转改变数值我们可以考虑用一个新的数组f[i]来解决。借助f[i](0或1)来存储每一个位置的反转情况,进而使得复杂度降低为O(N^2)基于此代码如下:

#include<iostream>
using namespace std;
#define MAXN 5000
int dir[MAXN];                   //牛的方向,0 F 1 B
int f[MAXN];                     //记录每个位置是否发生反转,奇数反转,偶数可视为没发生反转
int N;
int calc(int k)
{
	int i,sum=0,res=0;           //用sum记录i前面发生的对"当前"f[i]有影响的反转次数,res记录总的反转次数
	memset(f,0,sizeof(f));
	for(i=0;i+k<=N;i++)              //注意结束条件i>n-k,即i=n-k+1
	{
		if((dir[i]+sum)%2!=0)
		{
			res++;
			f[i]=1;
		}
		sum+=f[i];
		//sum的值来自于记录被反转的次数,若当前i超出k范围,
		//那么i+1-k及其前面位置发生的反转将不能影响当前i的反转次数,所以减去
		if(i+1>=k)
			sum-=f[i+1-k];                   

	}
	for(i=N-k+1;i<N;i++)
	{
		if((dir[i]+sum)%2!=0)
			return -1;
		if(i+1>=k)
			sum-=f[i+1-k];                   

	}
	return res;
}
void solve()
{
	int p,q,ans=N+1;
	for(int i=1;i<=N;i++)
	{
		p=calc(i);
		if(p!=-1)
		{
			ans=(ans<p?ans:p);
			q=i;
		}
	}
	cout<<q<<" "<<ans<<endl;
}
int main()
{
	cin>>N;
	char c;
	int i;
	for(i=0;i<N;i++)
	{
		cin>>c;
		dir[i]=(c=='F'?0:1);
		getchar();
	}
	solve();

	return 0;
}
时间: 2024-10-05 13:01:46

POJ 3276 Face The Right Way的相关文章

反转(开关问题) POJ 3276

POJ 3276 题意:n头牛站成线,有朝前有朝后的的,然后每次可以选择大小为k的区间里的牛全部转向,会有一个最小操作m次使得它们全部面朝前方.问:求最小操作m,再此基础上求k. 题解:1.5000头牛不是小数目,再怎么也得要n^2的算法,其中,枚举k是需要的,这就有n了,只能想办法给出一个n在O(n)时间内求出最小次数了. 2.对于给定的k,要想O(n)内把次数算出来,即只能扫一遍,一想到的必定是从前往后扫,遇到面朝后的就转头,但这一转牵扯太多,要改太多东西,k一大直接崩溃. 3.对于每次扫描

POJ 3276 Face The Right Way (常用技巧-尺取法)

[题目链接]:click here~~ [题目大意]:N头牛排成一列1<=N<=5000.每头牛或者向前或者向后.为了让所有牛都 面向前方,农夫每次可以将K头连续的牛转向1<=K<=N,求操作的最少 次数M和对应的最小K. [思路]:由于交换区间翻转顺序对结果没影响,所以从左往右对于需要  翻转的牛进行反转,同时记录对该区间其他牛的影响即cal中的sum, 对于最后部分无法翻转的区间检查是否有反向牛,若有则方案失败.此题思想值得细细思考,常常有一种无限状态,化为有限状态. 代码:

POJ 3276 [Face The Right Way] 题解

题目大意 n头牛排成一行,有的牛面朝前,有的牛面朝后,每一次操作可以使连续的K头牛改变方向:求一个K,使得操作次数最少.输出K以及最少的操作次数.当有多个K满足条件时,输出最小的K. 题目分析 对一个区间来说,多次进行反转操作是没有意义的:另外反转的顺序对结果是没有影响的.所以这道题只需要对所有的可操作区间(即长度为K的区间)考虑是否需要反转. 考虑最左边的牛,当它面朝前时无需反转,当它面朝后时,就反转[1, K]区间一次.然后继续考虑第二头牛即可. 反转的时候不必每头牛都操作一次,只需用一个t

POJ 3276 Face The Right Way 开关问题

Face The Right Way Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4367   Accepted: 2025 Description Farmer John has arranged his N (1 ≤ N ≤ 5,000) cows in a row and many of them are facing forward, like good cows. Some of them are facin

POJ 3276 (开关问题)

题目链接: http://poj.org/problem?id=3276 题目大意:有一些牛,头要么朝前要么朝后,现在要求确定一个连续反转牛头的区间K,使得所有牛都朝前,且反转次数m尽可能小. 解题思路: 首先不要看错题意了,不是求最小K,不要二分.而且反转区间长度一定是K,小于K是不能反转的. 很明显得枚举K(1...n),并且有以下反转思路: ①从第一头牛开始,如果朝前,不管了.看下一头牛,如果朝后反转K长度区间.....一直扫到区间结束. ②第一趟结束后,如果不符合要求,继续重复①,直到所

poj 3276 Face The Right Way 递推

地址  http://poj.org/problem?id=3276 解法 依次遍历一次翻转K(1~N)头牛的办法 最后得出转数最小的答案  复杂度是 N*N*N 但是在模拟一次翻转K头牛的时候 我们可以优化模拟翻转的过程 优化效率 如图 当K = 3 每次翻转3头牛的时候 第0头牛 朝后 之前影响到第0头牛的点击数为0 所以我们需要点击1次 将牛朝前 第1头牛 朝后 之前影响第1头牛的点击数为1 所以牛已经朝前不必点击 第2头牛 朝前 之前影响第2头牛的点击数为1 所以需要点击1次  将牛朝前

poj 3276(反转)

传送门:Problem 3276 参考资料: [1]:挑战程序设计竞赛 先献上AC代码,题解晚上再补 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define mem(a,b) (memset(a,b,sizeof(a))) 6 const int maxn=5e3+30; 7 8 int N; 9 int dir[maxn];//0:forw

poj 3276

开关反转问题,想法很巧妙,看了一节课才看懂,严重怀疑自己弱智....就难受 #include <iostream> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; const int maxn=5000+10; int a[maxn],f[maxn];//B:1,F:0 int n; int fan(int k) { int sum=0,ans=0;

POJ 3276 反转问题

#include <cstdio> #include <iostream> #include <cstring> using namespace std; int n; int a[5005][2]; int flag[5005]; int fun(int x){ int sum = 0; int res = 0; memset(flag,0,sizeof(flag)); for(int i = 0;i+x <= n;i++){ if(sum%2 == 0 &am

POJ 3276 The Cow Lexicon DP-字符串匹配

点击打开链接 The Cow Lexicon Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8325   Accepted: 3934 Description Few know that the cows have their own dictionary with W (1 ≤ W ≤ 600) words, each containing no more 25 of the characters 'a'..'z'.