反转问题

一维反转问题

POJ3276---Face The Right Way 

题目要求使得反转次数最少时每次连续反转个数最小值;可以枚举所有连续反转个数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;
}

二维反转

POJ3279---Fliptile

与一维反转一样,任何位置的反转超过一次都是无谓的,因而最后的结果矩阵的值只能为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;
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值