【题目链接】:click here~~
【题目大意】:N头牛排成一列1<=N<=5000。每头牛或者向前或者向后。为了让所有牛都 面向前方,农夫每次可以将K头连续的牛转向1<=K<=N,求操作的最少 次数M和对应的最小K。
【思路】:由于交换区间翻转顺序对结果没影响,所以从左往右对于需要 翻转的牛进行反转,同时记录对该区间其他牛的影响即cal中的sum, 对于最后部分无法翻转的区间检查是否有反向牛,若有则方案失败。此题思想值得细细思考,常常有一种无限状态,化为有限状态。
代码:
/************** *POJ 3276 (尺取法) *Face The Right Way * **************/ #include <iostream> #include <stdio.h> #include <string.h> using namespace std; const int N=5005; int t,n,m; int f[N]; //翻转状态,1翻转,0不翻转 int dir[N]; // 输入状态 F<>0 B<>1 char op[2]; int calc(int k){ //枚举k ,翻转顺序从左到右 memset(f,0,sizeof(f)); int i,res=0; // 连续翻转的次数 int sum=0; for(i=0; i+k<=n; ++i){ if((dir[i]+sum)&1){ //翻转奇数次改变状态,偶数次不改变 res++; f[i]=1; } sum+=f[i]; //尺取法 if(i-k+1>=0) sum-=f[i-k+1]; } for(; i<n; ++i){//判断剩下的是否有反向牛 if((dir[i]+sum)&1) return -1; else if(i-k+1>=0) sum-=f[i-k+1]; } return res; } void solve(){ int K=1,M=n; for(int i=1; i<=n; ++i){ int m=calc(i); if(m>0&&m<M){ M=m; K=i; } } printf("%d %d\n",K,M); } int main(){ while(scanf("%d",&n)!=EOF){ for(int i=0; i<n; ++i){ scanf("%s",op); if(op[0]=='F') dir[i]=0; else dir[i]=1; } solve(); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-13 15:13:49