一维反转问题
题目要求使得反转次数最少时每次连续反转个数最小值;可以枚举所有连续反转个数k(1<=k<=n),对于每一个k求出对应的反转次数;
容易想到,左端第一头牛只能被以它为开头的连续长度为k的区间覆盖,如果它朝后,那么必须进行一次反转,而且以后再次反转是无谓的,因而可以从一端开始计算;
若此时考虑第i头牛,它能够最多被以第i-k+1牛为开头的连续区间覆盖,因此可以考虑引入中间变量term,记录能够影响到它的区间反转次数之和,如果此时它的朝向(dir[i]+term)%2==1,那么以它为开头的连续区间必须反转,即f[i]=1;
一直到第i-k+2头牛时已经无法进行反转,此时考虑最后这几头牛是否朝前即可。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <string>
#include <cctype>
#include <cmath>
#include <map>
#include <vector>
#include <utility>
#define For(i,x,y) for(int i=(x);i<=(y);++i)
#define Fov(i,x,y) for(int i=(x);i>=(y);--i)
#define Fo(i,x,y) for(int i=(x);i<(y);++i)
#define midf(a,b) ((a)+(b)>>1)
#define L(_) (_)<<1
#define R(_) ((_)<<1)|1
#define fi first
#define se second
#define ss(_) scanf("%s",_)
#define si(_) scanf("%d",&_)
#define sii(x,y) scanf("%d%d",&x,&y)
#define siii(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define sl(_) scanf("%I64d",&_)
#define mem(x,y) memset(x,y,sizeof(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>P;
inline int read()
{
char ch=getchar(); int x=0, f=1;
while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();}
while('0'<=ch&&ch<='9') { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
const int inf=0x3f3f3f3f;
const double pi=acos(-1.0);
const int n_max=5e3+10;
int f[n_max],dir[n_max];
int compute(int k,int n)
{
memset(f,0,(n+1)*sizeof(int));
int term=n-k+1,now=0,res=0;
For(i,1,term)
{
if(i>k) now-=f[i-k];
if((dir[i]+now)&1)
{
++now;
++res;
f[i]=1;
}
}
For(i,term+1,n)
{
if(i>k) now-=f[i-k];
if((dir[i]+now)&1) return inf;
}
return res;
}
int main()
{
//freopen("in.txt","r",stdin);
int n; si(n);
char tp[5];
For(i,1,n)
{
ss(tp);
if(tp[0]=='F') dir[i]=0;
else dir[i]=1;
}
int ans=inf,k;
For(i,1,n)
{
int x=compute(i,n);
if(x<ans)
{
k=i;
ans=x;
}
}
printf("%d %d\n",k,ans);
return 0;
}
二维反转
与一维反转一样,任何位置的反转超过一次都是无谓的,因而最后的结果矩阵的值只能为0或1,而且为了防止无谓反转,应该确定一个大的反转顺序,就像一维反转中从一端到另一端,二维反转也可以考虑从最上行到最下行。
由于每次的反转都可以影响到左、上的方块,因而无法确定第一行的反转最优解,这时候可以枚举第一行的反转情况(opt矩阵保存最优解);对于第i行、第j列的方格,如果处于它的正上方的方格没有翻成白色,那么必须反转(i,j);最后还需检查最后一行是否都翻成白色来判断这种反转方式是否合理。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#include <string>
#include <cctype>
#include <cmath>
#include <map>
#include <vector>
#include <utility>
#define For(i,x,y) for(int i=(x);i<=(y);++i)
#define Fov(i,x,y) for(int i=(x);i>=(y);--i)
#define Fo(i,x,y) for(int i=(x);i<(y);++i)
#define midf(a,b) ((a)+(b)>>1)
#define L(_) (_)<<1
#define R(_) ((_)<<1)|1
#define fi first
#define se second
#define ss(_) scanf("%s",_)
#define si(_) scanf("%d",&_)
#define sii(x,y) scanf("%d%d",&x,&y)
#define siii(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define sl(_) scanf("%I64d",&_)
#define mem(x,y) memset(x,y,sizeof(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>P;
inline int read()
{
char ch=getchar(); int x=0, f=1;
while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();}
while('0'<=ch&&ch<='9') { x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
const int inf=0x3f3f3f3f;
const double pi=acos(-1.0);
int f[15][15],opt[15][15],tile[15][15];
int dx[4]={0,-1,0,0},dy[4]={0,0,1,-1},n,m;
int get(int x,int y)
{
int c=tile[x][y];
Fo(i,0,4)
{
int xx=x+dx[i],yy=y+dy[i];
if(xx>=0&&xx<m&&yy>=0&&yy<n) c+=f[xx][yy];
}
return c&1;
}
int compute()
{
int res=0;
Fo(j,0,n) res+=f[0][j];
Fo(i,1,m) Fo(j,0,n) if(get(i-1,j)) f[i][j]=1,++res;
Fo(j,0,n) if(get(m-1,j)) return inf;
return res;
}
int main()
{
//freopen("in.txt","r",stdin);
sii(m,n);
Fo(i,0,m) Fo(j,0,n) si(tile[i][j]);
int ans=inf;
Fo(i,0,1<<n)
{
mem(f,0);
Fo(j,0,n) f[0][n-j-1]=(i>>j)&1;
int tp=compute();
if(tp<ans)
{
memcpy(opt,f,sizeof(f));
ans=tp;
}
}
if(ans==inf) printf("IMPOSSIBLE\n");
else Fo(i,0,m) Fo(j,0,n) printf("%d%c",opt[i][j],j==n-1?'\n':' ');
return 0;
}