[toj2858]Puzzle Game全排列枚举

题目大意:给一个`4*4`的方格,内有4种字母:A,B,C,D.每种字母有且仅有4个,所以一共是16个字母.每次操作可以交换相邻的两个格子,问至少要操作多少次可以使其中某个2*2的小格子中字母相同.
刚开始没有理解清楚题目"每种字母有且仅有4个",所以感觉是一个状态压缩的搜索题.然后...TLE,内存耗了40+MB才发现自己没有去重...然后算了一下状态数量,我的妈呀,1000多万呐...后来想到是一个枚举.因为一共只能圈出9个2*2小方格,对每块2*2小方格,枚举四种字母就好了.事先排序,让字母的坐标和这四个格子分别对应:左上角的小格子装左上角的字母.然后...WA.百思不得解,后来想到可能存在不按上述贪心能得到更优解的情形,于是想到对于四个相同字母和一个指定的2*2小格子,分别尝试挪到四个位置,这样就有4!=24种,而不是上面贪心得到的1种了.总的状态数是9*4*24,是非常小的运算量
```C++
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
const int MAX = 5;

char str[MAX][MAX];
struct Node {
    int x, y;
    bool operator<(const Node B)const {
        return x==B.x ? y < B.y : x < B.x;
    }
} Map[MAX][MAX];
int ans[MAX];
int Fuck[4][2] = {0,0, 0,1, 1,0, 1,1};
int Dong[24][4] = {0, 1, 2, 3};
/* 把id+'A'字母移到以(x,y)为左上角的2x2小方格中需要多少步 */
int move(int x, int y, int id) {
    int sum, res = 0xffffff;
    
    int a[4];
    for (int i = 0; i < 24; ++i) {
        memcpy(a, Dong[i], sizeof(Dong[i]));//选取一个排列方式
        sum = 0;
    //计算按照这种排列移动的步数.步数计算公式是很显然的~
        for (int j = 0; j < 4; ++j) {
            sum += abs(Map[id][a[j]].x - (x+Fuck[j][0]));
            sum += abs(Map[id][a[j]].y - (y+Fuck[j][1]));
        }
        res = min(res, sum);
    }
    return res;
}

int solve(void) {
    int res = 0xfffff;
    for (int i = 0; i < 3; ++i) {
        for (int j = 0; j < 3; ++j) {
            for (int k = 0; k < 4; ++k) {
                res = min(res, move(i, j, k));//指定把字母k+'A'放到(i,j)&(i,j+1)&(i+1,j)&(i+1,j+1)的2*2格子中去
            }
        }
    }
    return res;
}
int main() {
    int tmp[4] = {0, 1, 2, 3}, idx = 1;
    while (next_permutation(tmp, tmp+4)) {
        memcpy(Dong+idx, tmp, sizeof(tmp));
        ++idx;
    }//获得4个数0~3构成的全排列
    int T;
    scanf(" %d", &T);
    while (T--) {
        for (int i = 0; i < 4; ++i) {
            scanf(" %s", str[i]);
        }
        int c[4] = {0};
        for (int i = 0; i < 4; ++i) {
            for (int j = 0; j < 4; ++j) {
                int t = str[i][j] - 'A';
                Map[t][c[t]].x = i, Map[t][c[t]].y = j;
                c[t]++;
            }
        }//记录每种字母对应的四个坐标
        for (int i = 0; i < 4; ++i) sort(Map[i], Map[i]+4);//这里不排序也可以,只是之前写贪心时这么做...
        printf("%d\n", solve());
    }
    return 0;
}
```


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值