Path-finding (implicit graph traversal)

Eight digital problem

:( Liu Rujia reference code "algorithm contest entry classic", the source code on the first page of the top area code repository

Encoding and decoding

//无权图上的最短路,可用BFS求解 
#include<bits/stdc++.h>
using namespace std;
const int MAX = 1000000;
typedef int State[9] ; // 定义“状态”类型

State st[MAX],goal;//状态数组

int dis[MAX];//距离数组
//ps: 如果需要答应路径, 可用在这加一个 father【MAX】 ,自己实现下吧

const int dx[] = {-1, 1, 0, 0};
const int dy[] = {0, 0, 1, -1};

int vis[MAX], fact[9]; 
void init_() {
    fact[0] = 1;
    for(int i = 1; i < 9; i++) fact[i] = fact[i-1] * i;
};
int try_to_insert(int rear) {
    int code = 0; // 将st[rear] 映射到整数code 
    // ps: 这里直接用st[rear]没有错, 因为bfs中用的是“引用”, st[rear]已更新
    for (int i = 0; i<9; i++)
    {
        int cnt = 0;
        for (int j = i + 1; j<9; j++)
            if (st[rear][j]<st[rear][i])cnt++;
        code += fact[8 - i] * cnt;
    }
    if (vis[code])return 0;
    return vis[code] = 1;
}

int bfs() {//bfs: 返回目标状态在st[]中的下标 (即goal在dis[] 中的下标 
    init_();//初始化查找表
    int front = 1, rear = 2; // 0 表示不存在, 找到的话返回front即可
    while(front < rear)  {
        State& s = st[front];//“引用” -- 换名字
        if(memcmp(goal, s, sizeof(s)) == 0) return front;//找到了目标位置,成功返回
        /*没有找到goal就继续扩展,而扩展得到的rear就可能是答案, 
        然后接下来继续while经memcpy找到答案时,返回的front即为上一次的rear, 对应的距离也就是上一次的dis[rear]了 
        所以,  binggo ! */
        int z;
        for(z = 0; z < 9; z++) if(!s[z] ) break;//找“0” 的位置
        int x = z / 3, y = z % 3; //获取0的行列编号
        for(int d = 0; d < 4; d++) {
            int nowx = x + dx[d], nowy = y + dy[d], nowz = nowx*3 + nowy;//获取新0的位置 
            if(nowx>=0 && nowy>=0 && nowx<3 && nowy<3) {
                State &t = st[rear]; // 再次“换名字”, 用以修改队尾元素
                memcpy(&t, &s, sizeof(s) ); //扩展新的结点
                t[nowz] = 0;
                t[z] = s[nowz];//移动
                dis[rear] = dis[front] + 1; //更新距离值
                if(try_to_insert(rear) ) rear++; // 如果成功插入查找表, 修改队尾指针 为什么要用 try_to_insert() ?

//用于判重, 防止重复扩充
            }
        }
        front++;  //继续while 
    }
    return 0;// 没有找到goal, 返回0 
} 

int main() {
    for(int i = 0; i < 9; i++) scanf("%d", &st[1][i]);
    for(int i = 0; i < 9; i++) scanf("%d", &goal[i]);
    int ans = bfs();
    if(ans == 0) printf("-1");//没找到
    else printf("%d",dis[ans]); 
    return 0;
}
/*
2 8 3 1 0 4 7 6 5
1 2 3 8 0 4 7 6 5
ans = 4
*/

hash technology

(PS; it is only 2,3 init_ () and try_to_insert () on making changes to prevent visual fatigue, causing discomfort

// hash in competition with a wide range of good Oh

const int hashsize = 1000003;
int  head[hashsize], next[hashsize];//往往有不同节点的哈希值相等, 这时把哈希值相同的状态组织成链表 
void init_() {
    memset(head, 0, sizeof(head));
};
int hash(State s) {
    int v = 0;
    for(int i = 0; i < 9; i++) v = v*10 + s[i];//将9个数字合成为九位数 
    return v % hashsize;// 确保hash 函数值是不超过 hash表 大小的非负整数 
}
int try_to_insert(int rear) {
    int h = hash(st[rear]);
    int i = head[h];
    while(i) { // 从表头开始查找链表
        if(memcpy(st[i], st[rear], sizeof(st[rear])) == 0) return 0;// 找到了, 插入失败 
        i = next[i];
    }// 本人在luogu 上测评时发现这的while 改成for 会RE掉...有人可以告诉我为啥吗, 还是建议你们写while吧 
    next[i] = head[h];
    head[h] = rear;// 
    return 1;
}

STL Dafa is good!

STL can be used as a springboard

          --- Liu Rujia

set <int> vis;
void init_() { vis.clear() ; }
int try_to_insert(int rear) {
    int v = 0;
    for(int i = 0; i < 9; ++i) v = v*10 + st[rear][i];
    if(vis.count(v) ) return 0; // vis.count() 若在vis里面, 返回1 
    vis.insert(v);
    return 1;  
}

Pour problem

description:

Title Description

There are three capacities of a, b, c liter container (a, b, c are positive integers, and not more than 200), the beginning of the first and second cups are empty, only the third cup filled with c liters of water. Allowing water from one container into another container until the container is empty or filled with another container, allowing an unlimited number of operations performed such pour.

Your task is to write a program to calculate the required minimum number of liters of water to allow water to pour one cup of which d l (d is a positive integer of not more than 200)? Failure to do exactly d liter, let one cup of water is d 'l, where d' <d and d as close as possible. If you can find such d ', you still need to figure out which one cup reaches d' when liter, the minimum required number of liters of water down.

Input and output formats

Input formats:

The first line of the input is an integer T, represents a set of test data. Next T lines, each line separated by a space 4 respectively represent integers a, b, c, d.

Output formats:

For each test, an output line, comprising two integers, the first integer represents the total amount of pour least, the second integer represent the target pour water (d or d ').

Sample input and output

Input Sample # 1:

2
2 3 4 2
96 97 199 62

Output Sample # 1:

2 2
9859 62

Code

#include<cstdio>
#include<string.h>
#include<queue>
using namespace std;
#define MAX 200+99

int T; 

struct node{
    int v[3], dis;//注:这是最少倒水量,所以用堆 
    bool operator < (const node& rhs) const {
        return dis > rhs.dis ;
    }
};

int vis[MAX][MAX], cap[3], goal,ans[MAX];//ans[i]表示到成i升的水的最小倒水量

void update(node x) {
    for(int i = 0; i <= 2; i++) {
        if(ans[i] < 0 || ans[i] > x.dis ) {
            ans[i] = x.dis ;
        }
    }
    return ;
} 

void solve() {
    memset(vis, 0, sizeof(vis));
    memset(ans, -1, sizeof(ans));//有可能ans为0 
    priority_queue<node> q;//在里面定义好

    node u,e,start;
    start.dis = 0,start.v[0] = start.v[1] = 0, start.v[2] = cap[2];
    q.push(start); 
    while(!q.empty() ) {
        u = q.top() ; q.pop() ;
        update(u);
        if(ans[goal] >= 0) break;
        //if(vis[u.v[0]][u.v[1]]]) continue ;// 试试 
        for(int i = 0; i <= 2; i++) //i往j里加 
            for(int j = 0; j <= 2; j++) if(j != i) {
                if(u.v[i] == 0 || u.v[j] == cap[j]) continue;
                int tmp = min(cap[j]-u.v[j], u.v[i]);
                memcpy(&e, &u, sizeof(u));
                e.dis = u.dis + tmp;
                e.v[i] -= tmp, e.v[j] += tmp;
                if(!vis[e.v[0]][e.v[1] ]) {
                    q.push(e);
                    vis[e.v[0]][e.v[1] ] = 1;
                }
            } 
            
    }
    while(goal >= 0) {
        if(ans[goal] >= 0) {
            printf("%d %d\n", ans[goal], goal);
            return ;
        }
        goal--;
    }
}

int main() {
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d%d%d",&cap[0],&cap[1],&cap[2],&goal);
        solve();
        
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/tyner/p/11080392.html