Word UVA - 517 状态压缩 暴力搜索

问题

https://vjudge.net/problem/UVA-517

分析

每次都循环到字典序最小的时候记录。
一共最多有 2 1 6 2^16 216种,因为每种状态都变到字典序最小的时候,所以实际的远小于 2 1 6 2^16 216,使用map保存。
先求出一次循环时的长度T,起始点a,终止点b,T=b-a, 答案是第(s-a)%T+a种状态。
注意序号:输入时数组中是 0,1,2…i,i+1,i+2,转到二进制后是0,1,2…i-2,i-1,i,i+1, 不能是i+2,i+1,i,i-1,i-2(因为这样就反向了,相当于翻转了)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long LL;
const int maxn=(1<<15)+100;
int n,s,kase=0,vis[maxn],rule[8];
char a[100];
vector<int> rec;

inline int minlexico(int temp){
    int t=temp,flag=0;
    for(int i=0;i<n;++i){
        flag=temp>>(n-1);
        temp&=(1<<(n-1))-1;
        temp<<=1;
        temp|=flag;
        if(temp<t) t=temp;
    }
    return t;
}

inline int getindex(int c1,int c2,int c3){
    return (c1<<2)+(c2<<1)+c3;
}

int solve(int start){
    int k=1,op=0,ed=0;
    for(;;++k){
        int rewriting=0;
        for(int i=0;i<n;++i){
            int c1=((i+2)>=n?(start&(1<<(i+2-n))):(start&(1<<(i+2))))?1:0;
            int c2=(start&(1<<i))?1:0;
            int c3=((i-1)>=0?(start&(1<<(i-1))):(start&(1<<(i-1+n))))?1:0;

            rewriting|=(rule[getindex(c1,c2,c3)]<<i);
        }
        rewriting=minlexico(rewriting);
        rec.push_back(rewriting);
        if(s==k) return rewriting;
        if(vis[rewriting]!=-1){
            op=vis[rewriting];
            ed=k;
            break;
        }
        start=rewriting;
        vis[rewriting]=k;
    }
    return rec[(s-op)%(ed-op)+op];
}

int main(void){
    while(scanf("%d",&n)==1){
        rec.clear();
        memset(vis,-1,sizeof(int)*((1<<n)+10));
        int start=0;
        scanf("%s",a);
        for(int i=0;i<n;++i){
            if(a[i]=='b'){
                start|=(1<<(n-1-i));
            }
        }
        start=minlexico(start);
        vis[start]=0;
        rec.push_back(start);
        char ch[10];
        for(int i=0;i<8;++i) {
            scanf("%s",ch);
            rule[getindex(ch[0]-'a',ch[1]-'a',ch[2]-'a')]=ch[3]-'a';
        }
        scanf("%d",&s);
        int ans=solve(start);
        for(int i=n-1;i>=0;--i){
            if(ans&(1<<i)){
                putchar('b');
            }else putchar('a');
        }
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值