爬格子呀--一堆东西

好久没上传了,主要是因为期中考试的复习,没有足够的时间来写
期中考试大物不及格,但是数学建模校赛却拿到了二等奖,塞翁失马吧
好几道题这次是,发现越来越难了,但却好像又有规律可循
代码如下:

Uva1343旋转游戏

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int a[24];
char ans[10000];
//表格的线性化
/*
      00    01
      02    03
04 05 06 07 08 09 10
      11    12
13 14 15 16 17 18 19
      20    21
      22    23
*/

int mat[8][7] = {
    { 0,2,6,11,15,20,22 },//A 0
    { 1,3,8,12,17,21,23 },//B 1
    { 10,9,8,7,6,5,4 },//C 2
    { 19,18,17,16,15,14,13 },//D 3 
    { 23,21,17,12,8,3,1 },//E 4
    { 22,20,15,11,6,2,0 },//F 5
    { 13,14,15,16,17,18,19 },//G 6
    { 4,5,6,7,8,9,10 },//H 7
};

int center[8] = { 6,7,8,11,12,15,16,17 };

//判断是否达到最终情况
bool tar() {
    for (int i = 0; i < 8; i++) 
        if (a[center[i]] != a[center[0]])
            return false;
    return true;
}
//寻找1、2、3三个数在中圈中的数值与目标不一样的个数,数量越小,表示1、2、3在中圈中的个数越多
int time(int k) {
    int ans = 0;
    for (int i = 0; i < 8; i++) {
        if (a[center[i]] != k)
            ans++;
    }
    return ans;
}

//寻找最小值
int find_min() {
    return min(min(time(1), time(2)), time(3));
}

//移动棋盘序列
void move(int i) {
    int mid = a[mat[i][0]];
    int j = 0;
    for (; j < 6; j++) {
        a[mat[i][j]] = a[mat[i][j + 1]];
    }
    a[mat[i][6]] = mid;
}

//dfs建立在递归的基础上
//这个dfs用到了IDA*的算法进行剪枝,d为深度,maxd为目标上限find_min为乐观估价函数,与深度相加判断是否越界
bool dfs(int d, int maxd) {
    //与dfs类似,优先判断是否满足条件
    if (tar()) {
        for (int i = 0; i < d; i++) {
            putchar(ans[i]);
        }
        //ans[d] = '';
        //printf("%s
", ans);
        return true;
    }
    //IDA*的判断
    if (d + find_min() > maxd)
        return false;
    int t[24];
//  memcpy(t, a, sizeof(a));
    for (int i = 0; i < 8; i++) {
        ans[d] = 'A' + i;
        //这一步的ans[d]很关键,因为d只有在这一次迭代成功的时候才会改变
        //这就保证了可以通过循环来深度遍历,并且不断的更新
        move(i);
        if (dfs(d + 1,maxd))
            return true;
        //若失败,则清除上面的移动
        //memcpy(a, t, sizeof(a));
        int mid = (i + 4) % 8;
        mid % 2 == 0 ? move(mid + 1) : move(mid - 1);
    }
    return false;
}

int main() {
    while (scanf("%d",&a[0]), a[0]!=0) {
        for (int i = 1; i < 24; i++)
            scanf("%d", &a[i]);
        if (tar())
            printf("No moves needed");
        else
            for (int maxd = 1; ; maxd++)
                if (dfs(0,maxd));
                    break;
        printf("%d", a[center[0]]);
    }
    return 0;
}

Uva818–切断圆环链

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<deque>
#include<utility>
using namespace std;
typedef pair<int, int> p;
const int maxn = 15;
int node, n, t;
deque<p>store[maxn + 1];

bool can_find(int i, p pp) {
    for (deque<p>::iterator it=store[i].begin();it!=store[i].end(); advance(it,1))
        if ((*it).first == pp.first) {
            if (it == store[i].begin()) {
                store[i].push_front(make_pair(pp.second, pp.first));
                return true;
            }
            node++;
            store[++t].push_back(pp);
            return true;
        }
    return false;
}

int main() {
    p pp;
    scanf("%d", &n);
    scanf("%d %d", &pp.first, &pp.second);
    store[t].push_back(pp);
    while (n != 0) {
        scanf("%d %d", &pp.first, &pp.second);
        if (pp.first == -1 && pp.second == -1)
            break;
        for (int i = 0; i <= t; i++) {
            int size = store[i].size();
            if (size == 0) {
                store[i].push_back(pp);
                break;
            }
            //判断能否插入到末尾
            if (store[i][size - 1].second == pp.first)
            {
                store[i].push_back(pp);
                //判断是否为大环
                if (store[i][0].first == pp.second) {
                    node++;
                    t++;
                    break;
                }
                break;
            }
            //判断是否为一环套多环
            else if (can_find(i, pp))
                break;
        }
    }
    printf("%d", node);
    return 0;
}

Uva1602–网格动物

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
const int maxn = 10;
int n, w, h;
int dir[4][2] = { { 0,1 },{ 0,-1 },{ 1,0 },{ -1,0 } };

struct cell {
    int x, y;
    cell(int x = 0, int y = 0) :x(x), y(y) {};//函数包含默认构涵,可以显示的构造自己想要的特定结构体
    bool operator < (const cell &rhs)const {
        return x < rhs.x || (x == rhs.x && y < rhs.y);
    }
};

#define FOR_CELL(c,p) for(set<cell>::const_iterator c=(p).begin();c!=(p).end();c++)
//规范化,根据书上面讲的,应该是想通过做差值来减少运算量???
inline set<cell> normalize(const set<cell>&p) {
    int minx = p.begin()->x, miny = p.begin()->y;
    FOR_CELL(c, p) {
        minx = min(minx, c->x);
        miny = min(miny, c->y);
    }
    set<cell>pp;
    FOR_CELL(c, p) {
        pp.insert(cell(c->x - minx, c->y - miny));
    }
    return pp;
}
//旋转,坐标运算
inline set<cell> rotate(const set<cell>&p) {
    set<cell>pp;
    FOR_CELL(c, p) {
        pp.insert(cell(c->y, -c->x));
    }
    return normalize(pp);
}
//对称,坐标运算
inline set<cell> flip(const set<cell>&p) {
    set<cell>pp;
    FOR_CELL(c, p) {
        pp.insert(cell(c->x, -c->y));
    }
    return normalize(pp);
}

set<set<cell>>poly[maxn + 1];
int ans[maxn + 1][maxn + 1][maxn + 1];//三维数组,表示三个限定条件下的结果,这个是提前计算的需要

//检查,如果点new_cell无法通过p中已有的点的坐标变化得到,就说明p是一个新的点,将其加入到点集中
void check(const set<cell>& p, const cell &new_cell) {
    set<cell>pp = p;
    pp.insert(new_cell);
    pp = normalize(pp);
    int n = pp.size();
    for (int i = 0; i < 4; i++) {
        if (poly[n].count(pp) != 0)
            return;
        pp = rotate(pp);
    }
    pp = flip(pp);
    for (int j = 0; j < 4; j++) {
        if (poly[n].count(pp) != 0)
            return;
        pp = rotate(pp);
    }
    poly[n].insert(pp);
}
//计算函数
void generate() {
    set<cell>s;
    s.insert(cell(0, 0));
    poly[1].insert(s);
    //网格多边形从1开始
    for (int n = 2; n <= maxn; n++) {
        for (set<set<cell>>::iterator p = poly[n - 1].begin(); p != poly[n - 1].end(); p++) {
            FOR_CELL(c, *p)
                for (int i = 0; i < 4; i++) {
                    cell new_cell(c->x + dir[i][0], c->y + dir[i][1]);
                    if (p->count(new_cell) == 0)
                        check(*p, new_cell);
                }
        }
    }
    //提前计算,逆回归过程
    for (int n = 1; n <= maxn; n++)
        for (int w = 1; w <= maxn; w++)
            for (int h = 1; h <= maxn; h++) {
                int num = 0;
                for (set<set<cell>>::iterator p = poly[n].begin(); p != poly[n].end(); p++) {
                    int maxx = 0, maxy = 0;
                    FOR_CELL(c, *p) {
                        maxx = max(maxx, c->x);
                        maxy = max(maxy, c->y);
                    }
                    if (min(maxx, maxy) < min(w, h) && max(maxx, maxy) < max(w, h))
                        num++;
                }
                ans[n][w][h] = num;
            }
}

int main() {
    generate();
    while (scanf_s("%d%d%d", &n, &w, &h) == 3) {
        printf("%d
", ans[n][w][h]);
    }
    return 0;
}

Uva11214–守卫棋盘(八皇后改版)

#include<cstdio>
#include<iostream>
#include<string>
#include<memory.h>
using namespace std;
int map[15][15], vis[4][15];
int kase, maxn, m, n;

bool check() {
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (map[i][j] && !vis[0][i] && !vis[1][j] && !vis[2][i + j] && !vis[3][n - i + j])
                return false;
        }
    }
    return true;
}

bool dfs(int cur,int d,int ma_xn) {
    if (d == ma_xn) {
        if (check()) {
            printf("Case %d: %d
", ++kase, d);
            return true;
        }
        return false;
    }
    for (int i = cur; i < n*m; i++) {
        int x = i / m, y = i%m;
        int midx = vis[0][x], midy = vis[1][y], mid_d1 = vis[2][x + y], mid_d2 = vis[3][n - x + y];
        vis[0][x] = vis[1][y] = vis[2][x + y] = vis[3][n - x + y] = 1;
        if (dfs(i, d + 1, ma_xn))
            return true;
        vis[0][x] = midx, vis[1][y] = midy, vis[2][x + y] = mid_d1, vis[3][n - x + y] = mid_d2;
    }
    return false;
}

int main() {
    while (scanf("%d", &n) && n) {
        scanf("%d", &m);
        char s[15];
        memset(map, 0, sizeof(map));
        for (int i = 0; i < n; i++) {
            scanf("%s", s);
            for (int j = 0; j < m; j++) {
                if (s[j] == 'X')
                    map[i][j] = 1;
            }
        }
        for(maxn=0;;maxn++){
            memset(vis, 0, sizeof(vis));
            if (dfs(0, 0, maxn))
                break;
        }
    }
    return 0;
}

Uva817–数字表达式

#include<cstdio>
#include<iostream>
#include<string>
#include<stack>
#include<deque>
using namespace std;
char symbol[4] = { '*','+','-',' ' };
char num[20], sign[20];
int kase, amount, len;
int num2[20];
deque<int>tar, ans;

bool ok() {
    //tar储存数字,notation储存符号;
    int len2 = strlen(sign);
    int mid, i, j;
    for (i = len2 - 1, mid = 0; i >= 0; i--) {
        if (!isdigit(sign[i])) {
            mid = 0;
            tar.push_front(mid);
            continue;
        }
        mid = mid * 10 + num[i] - '0';
    }
    deque<int>::iterator it = tar.begin();
    for (i = 0; i < strlen(sign); i++) {
        if (!isdigit(sign[i])) {
            if (sign[i] == '*') {
                tar[i] *= tar[i + 1];
                advance(it, i + 1);
                tar.erase(it);
                it = tar.begin();
            }
            else if (sign[i] == '+') {
                tar[i] += tar[i + 1];
                advance(it, i + 1);
                tar.erase(it);
                it = tar.begin();
            }
            else {
                tar[i] -= tar[i + 1];
                advance(it, i + 1);
                tar.erase(it);
                it = tar.begin();
            }
        }
        else
            continue;
    }
    if (tar[0] == 2000) {
        for (i = 0; i < tar.size()-1; i++) {
            char *pp = (char*)&tar[i];
            ans.push_back(*pp);
            ans.push_back(sign[i]);
        }
        char *pp = (char*)&tar[i];
        ans.push_back(*pp);
        return true;
    }
    else
        return false;
}

void dfs(int d) {
    if (d + 2 == len) {
        if (ok())
            printf("  %s=
", ans), amount++;
        return;
    }
    for (int i = 0; i < 4; i++) {
        sign[d] = symbol[i];
        dfs(d + 1);
    }
}

int main() {
    while (scanf("%s", num) == 1 && num[0] != '=') {
        memset(sign, '0', sizeof(sign));
        amount = 0;
        len = strlen(num);
        for (int i = 0; i < len - 2; i++)
            num2[i] = num[i] - '0';
        dfs(0);
        printf("Problem %d", ++kase);
        if (!amount)
            printf("IMPOSSIBLE");
    }
    return 0;
}

Uva12107–数字谜

//copy from liudongbohehe
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
char s[3][6];
int len[3], maxd;
char change[12] = "*0123456789";

bool check_result() {
    char check_str[12];
    char ss[12];
    int t0 = 0, t1 = 0, t2;
    for (int i = 0; i < len[0]; i++)
        t0 = t0 * 10 + s[0][i] - '0';
    for (int i = 0; i < len[1]; i++)
        t1 = t1 * 10 + s[1][i] - '0';
    t2 = t0*t1;
    //上面计算出t2之后,这一步是用t2对check_str[]进行一个逆向的填充
    for (int i = 0; i < len[2]; i++) {
        check_str[len[2] - i - 1] = t2 % 10 + '0';//先填充高位的方法
        t2 /= 10;
    }
    //检查是否t2被除尽以及首字符是否为0
    if (t2 != 0 || check_str[0] == '0')
        return 0;
    for (int i = 0; i < len[2]; i++) 
        if (check_str[i] != s[2][i] && s[2][i] != '*')
            return 0;
    return 1;
}

//这个检查其实也是一个dfs
int check(int a, int b) {
    int flag = 0;
    if (a == 2)
        return check_result();
    int ta, tb;
    char ch = s[a][b];
    if (len[a] - 1 == b) {
        ta = a + 1;
        tb = 0;
    }
    else {
        ta = a;
        tb = b + 1;
    }
    if (s[a][b] == '*') {
        for (int i = 1; i < 11; i++) {
            if (b == 0 && i == 1)
                continue;
            s[a][b] = change[i];
            flag += check(ta, tb);
            if (flag > 1)
                break;
        }
    }
    else flag += check(ta, tb);
    s[a][b] = ch;
    return flag;
}

//dfs+IDA*
bool dfs(int a, int b, int d, int max_d) {
    int flag = 0;
    //如果深度等于阈值,则进行判断
    if (d == max_d) {
        if (check(0, 0)==1)
            return true;
        else
            return false;
    }
    if (a == 3)
        return false;
    int ta, tb;
    //tmp保存数值,dfs每次迭代的对象是目标数组中的每个元素
    char tmp = s[a][b];
    if (b == len[a] - 1) {
        ta = a + 1;
        tb = 0;
    }
    else {
        ta = a;
        tb = b + 1;
    }
    //依次枚举
    for (int i = 0; i < 11; i++) {
        if (b == 0 && i == 1)
            continue;
        if (tmp == change[i]) {//判断是否需要替换数字
            s[a][b] = tmp;
            flag = dfs(ta, tb, d, max_d);//没有换数字所以没有进行深度的叠加
        }
        else {
            s[a][b] = change[i];
            flag = dfs(ta, tb, d + 1, max_d);
        }
        if (flag)
            break;
    }
    if (!flag)//没有找到,迭代失败,归还原值
        s[a][b] = tmp;
    return flag;
}

int main() {
    int kase=0;
    memset(s, '0', sizeof(s));
    while (1) {
        scanf("%s", s[0]);
        if (s[0][0] == '0')
            break;
        scanf(" %s %s", s[1], s[2]);
        for (int i = 0; i < 3; i++)
            len[i] = strlen(s[i]);
        //maxd = 0;
        for (maxd = 0;; maxd++) {
            //IDA*
            if (dfs(0, 0, 0, maxd))
                break;
        }
        printf("Case %d: %s %s %s
", ++kase, s[0], s[1], s[2]);
        memset(s, '', sizeof(s));
    }
    return 0;
}

Uva690–流水线调度

//copy from xuli
#include<cstdio>
#include<iostream>
#include<string>
#include<memory.h>
#include<algorithm>
using namespace std;
int n, ans, ndis;
int table[5], dis[24];
string str;

void dfs(int t[5], int d, int len) {
    if (d == 10) {
        ans = min(len, ans);
        return;
    }
    if (len + dis[0] * (10 - d) >= ans)
        return;
    for (int i = 0; i < ndis; i++) {
        int tmpdis = dis[i];
        bool flag = true;
        for (int j = 0; j < 5; j++) {
            if ((t[j] >> tmpdis)&table[j])
                flag = false;
        }
        if (!flag)
            continue;
        int tmpt[5];
        for (int j = 0; j < 5; j++)
            tmpt[j] = (t[j] >> tmpdis) | table[j];
        dfs(tmpt, d + 1, len + tmpdis);
    }
    return;
}

int main() {
    while (scanf("%d",&n) && n) {
        memset(table, 0, sizeof(table));
        for (int i = 0; i < 5; i++) {
            cin >> str;
            for (int j = 0; j < n; j++) {
                if (str[j] == 'X') {
                    table[i] |= (1 << j);
                }
            }
        }
        ans = n * 10;
        ndis = 0;
        bool b;
        for (int i = 1; i <= n; i++) {
            b = true;
            for (int j = 0; j < 5; j++) {
                if (table[j] & (table[j] >> i))
                    b = false;
            }
            if (b)
                dis[ndis++] = i;
        }
        dfs(table, 1, n);
        printf("%d", ans);
    }
    return 0;
}

Uva12113–重叠的正方形

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<memory.h>
using namespace std;
//string ini[5], tar[5];
char ini[10][15], tar[10][15];
int vis[9];

bool dfs(int cur) {
    bool flag = false;
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 9; j++) {
            if (ini[i][j] != tar[i][j]) {
                flag = true;
                break;
            }
        }
        if (flag)
            break;
    }       
    if (!flag)
        return true;
    if (cur >= 6)
        return false;
    char save[10][15];
    memcpy(save, ini, sizeof(ini));
    for (int i = 0; i < 9; i++) {
        if (!vis[i]) {
            int r = i / 3, c = (i % 3) * 2 + 1;
            ini[r][c] = ini[r][c + 2] = ini[r + 2][c] = ini[r + 2][c + 2] = '_';
            ini[r + 1][c - 1] = ini[r + 2][c - 1] = ini[r + 1][c + 3] = ini[r + 2][c + 3] = '|';
            ini[r + 1][c] = ini[r + 1][c + 1] = ini[r + 2][c + 1] = ini[r + 1][c + 2] = ' ';
            vis[i] = 1;
            if (dfs(cur + 1))
                return true;
            memcpy(ini, save, sizeof(save));
            vis[i] = 0;
        }
    }
    return false;
}

int main() {
    int kase = 0;
    while (1) {
        memset(tar, 0, sizeof(tar));
        scanf("%c", &tar[0][0]);
        if (tar[0][0] == '0')
            break;
        for(int i=1;i<9;i++)
            scanf("%c", &tar[0][i]);
        getchar();
        getchar();
        for (int i = 1; i < 5; i++) {
            for (int j = 0; j < 9; j++) {
                scanf("%c", &tar[i][j]);
            }
            getchar();
            getchar();
        }
        memset(ini, ' ', sizeof(ini));
        memset(vis, 0, sizeof(vis));
        printf("Case %d: ", ++kase);
        if (dfs(0))
            printf("Yes
");
        else
            printf("No
");
    }
    return 0;
}

继续加油~~

原文地址:https://www.cnblogs.com/romaLzhih/p/9489850.html