uva 11198 Dancing Digits(隐式图搜索+哈细判重)

737 篇文章 0 订阅

Dancing Digits

Digits like to dance. One day, 1, 2, 3, 4, 5, 6, 7 and 8 stand in a line to have a wonderful party. Each time, a male digit can ask a female digit to dance with him, or a female digit can ask a male digit to dance with her, as long as their sum is a prime. Before every dance, exactly one digit goes to who he/she wants to dance with - either to its immediate left or immediate right.

For simplicity, we denote a male digit x by itself x, and denote a female digit x by -x. Suppose the digits are in order {1, 2, 4, 5, 6, -7, -3, 8}. If -3 wants to dance with 4, she must go either to 4's left, resulting {1, 2, -3, 4, 5, 6, -7, 8} or his right, resulting {1, 2, 4, -3, 5, 6, -7, 8}. Note that -3 cannot dance with 5, since their sum 3+5=8 is not a prime; 2 cannot dance with 5, since they're both male.

Given the initial ordering of the digits, find the minimal number of dances needed for them to sort in increasing order (ignoring signs of course).

Input

The input consists of at most 20 test cases. Each case contains exactly 8 integers in a single line. The absolute values of these integers form a permutation of {1, 2, 3, 4, 5, 6, 7, 8}. The last case is followed by a single zero, which should not be processed.

Output

For each test case, print the case number and the minimal number of dances needed. If they can never be sorted in increasing order, print -1.

Sample Input

1 2 4 5 6 -7 -3 8
1 2 3 4 5 6 7 8
1 2 3 5 -4 6 7 8
1 2 3 5 4 6 7 8
2 -8 -4 5 6 7 3 -1
0

Output for the Sample Input

Case 1: 1
Case 2: 0
Case 3: 1
Case 4: -1
Case 5: 3

题目大意:给出一串数字,正数代表男的,负数代表女的,任何一个数字可以邀请其他数字与它跳舞(移动到该数字的左边或者右边),前提是两个数字的绝对值之和必须是素数,且性别不同(一个正一个负),问,最少要多少次邀请可以使得排列从小到大(不考虑符号)。

解题思路:隐式图搜索+哈稀判断重复,对于每个状态,对每个数字开始遍历,找到与之“可邀请的数字”,移动到它的左边和右边(都要考虑),一开始很快就写好了,但是在判重的函数中将memcmp写成了memcpy,结果案例过了,交上去总是RE,因为判重的作用没有了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
using namespace std;

typedef int State[8];
const int MAXN = 1000005;
const int prime[20] = {0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1};

State order, rec, g[50000];
int head[MAXN], next[MAXN], dist[MAXN];

int cmp(const int &a, const int &b) {
    return abs(a) < abs(b);
}

void inInit() {
    memset(head, 0, sizeof(head));
    dist[0] = 0;
    memcpy(g[1], rec, sizeof(rec));
}

void inSert(State& s, int u, int v, int dir) {
    if(dir == 1){ //左边  
	if(u == v - 1) return;  // 如果本来就在他的左边,不移动  
	if(u == v + 1){ // 如果再它右边,直接交换  
	    int tmp = s[u];  s[u]=s[v]; s[v] = tmp;  
	}  
	int t = s[u];  
	if(u > v){  
	    for(int i = u; i > v; --i) s[i] = s[i-1];  
	    s[v] = t;  
	}  
	else{  
	    for(int i = u; i < v - 1; ++i) s[i] = s[i+1];  
	    s[v-1] = t;  
	}   
    }  
    else{ // 右边  
	if(u == v + 1) return ; //如果本来就在他右边, 不移动  
	if(u == v - 1){   
	    int tmp = s[u];  s[u]=s[v]; s[v] = tmp;  
	}  
	int t = s[u];  
	if(u > v){  
	    for(int i = u; i > v + 1; --i) s[i] = s[i - 1];  
	    s[v+1] = t;  
	}  
	else{  
	    for(int i = u; i < v; ++i) s[i] = s[i + 1];  
	    s[v] = t;  
	}   
    }  
}

int hash(State now) {
    int sum = 0; 
    for (int i = 0; i < 8; i++)
	sum = sum * 10 + now[i];
    return (sum & 0x7FFFFFFF) % MAXN;
}


bool tryInsert(int cur) {
    int h = hash(g[cur]);
    int u = head[h];
    while (u) {
	if(memcmp(g[u], g[cur], sizeof(g[cur])) == 0)
	    return false;
	u = next[u];
    }
    next[cur] = head[h];
    head[h] = cur;
    return true;
}

int bfs() {
    inInit();
    int front = 1, rear = 2;

    while (front < rear) {
	State& now = g[front];
	if (memcmp(now, order, sizeof(order)) == 0) 
	    return dist[front];

	for (int i = 0; i < 8; i++) {
	    for (int j = 0; j < 8; j++) {
		if (i != j && prime[abs(now[i]) + abs(now[j])] && now[i] * now[j] < 0){
		    for (int dir = 1; dir <= 2; dir++) {
			State& next = g[rear];
			memcpy(&next, &now, sizeof(now));
			inSert(next, i, j, dir);
			if (tryInsert(rear))
			    dist[rear++] = dist[front] + 1;
		    }
		}
	    }
	}
	front++;
    }
    return -1;
}

int main(){
    int cas = 1;
    while (scanf("%d", &rec[0]) == 1 && rec[0]) {
	// Read;
	for (int i = 1; i < 8; i++)
	    scanf("%d", &rec[i]);
	memcpy(order, rec, sizeof(rec));

	sort(order, order + 8, cmp);

	int flag = bfs();

	printf("Case %d: %d\n", cas++, flag);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值