Fork me on GitHub

Uva 11198 - Dancing Digits

Problem D

Dancing Digits

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=112&page=show_problem&problem=2139

题目意思:

给你{1,2,3,4,5,6,7,8}的一个排列,其中每个数带负号或带正号,通过插入的方法将这些数按绝对值从小到大排序,输出插入的最小步数,如果不可能完成输出-1,能否插入的要求是:你要根据其余的一个数嵌入其左边或右边,这个数跟你要插入的数不同符号,且绝对值相加必须得是素数,所以根据一个数为中心你可以插入其左或其右。

解题思路:

#BFS+Hash# 哈希选择了康托展开,用队列存储每一个状态,且用visit[对应哈希值]表示是否已访问过。思路清晰 了就好办,主要是看状态转移的时候是怎样一个转移法,首先要顾及每一个数共需要两个for循环,把每两个数都判断一遍,判断的要求就是一正一负,绝对值相加是素数,然后还要分情况放左边还是右边,我花的时间主要是在写插入函数那里,具体思路看代码实现(画图找规律是王道啊)。一开始你得判断几个特殊情况。

  1 #include<iostream>
  2 #include<string>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<cmath>
  6 #include<queue>
  7 #define MAXN 40322
  8 #define SIZE 8
  9 using namespace std;
 10 
 11 typedef int State[SIZE];
 12 typedef struct Status{
 13     State value;
 14 }Status;
 15 
 16 queue<Status>queuing;
 17 
 18 int st[MAXN];
 19 bool visit[MAXN];
 20 bool Prime[2*SIZE];
 21 int factory[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320};
 22 int start = -1;
 23 int dir[] = {1, -1};
 24 int input[SIZE];
 25 
 26 void getPrime()
 27 {//存储需要的素数
 28     memset(Prime, false, sizeof(Prime));
 29     for(int i=2; i<2*SIZE; ++i)
 30     {
 31         if(!Prime[i])
 32         {
 33             for(int j=i+i; j<2*SIZE; j += i)
 34                 Prime[j] = true;
 35         }
 36     }
 37     return;
 38 }
 39 
 40 int try_to_insert(int s[])
 41 {//返回对应的康托展开
 42     int sum = 0;
 43     for(int i=0; i<SIZE; ++i)
 44     {
 45         int cnt = 0;
 46         for(int j=i+1; j<SIZE; ++j)
 47             if(fabs(s[i])>fabs(s[j])) ++cnt;
 48         sum += cnt*factory[SIZE-i-1];
 49     }
 50     return sum;
 51 }
 52 
 53 bool isExchange(int a, int b)
 54 {//判断两个对应的数能否插入,可以返回true否则false
 55 
 56     if((a>0 && b<0) || (a<0 && b>0))
 57     {
 58         if(a>0) b = -b;
 59         else a = -a;
 60         if(!Prime[a+b]) return true;
 61     }
 62     return false;
 63 }
 64 
 65 void Translate(int s[], int to, int from, int kind)
 66 {//插入的函数,kind = -1 表示from位置的数插入到to位置的左边,kind = 1 表示插入到to位置的右边
 67     State p;
 68     int temp_to = s[to], temp_from = s[from];
 69     bool flag = false;
 70     s[to] = s[from] = 0;
 71     if(kind == -1)
 72     {
 73         for(int i=SIZE-1, j=SIZE-1; i>=0; )
 74         {
 75             if(s[j] != 0) p[i--] = s[j--];
 76             else if(flag == false)
 77             {
 78                 if(to > from)
 79                 {
 80                     p[i--] = temp_to;
 81                     p[i--] = temp_from;
 82                 }
 83                 j--;
 84                 flag = true;
 85             }
 86             else
 87             {
 88                 if(to < from)
 89                 {
 90                     p[i--] = temp_to;
 91                     p[i--] = temp_from;
 92                 }
 93                 j--;
 94             }
 95         }
 96     }
 97     else
 98     {
 99         for(int i=0, j=0; i<SIZE; )
100         {
101             if(s[j] != 0) p[i++] = s[j++];
102             else if(flag == false)
103             {
104                 if(to < from)
105                 {
106                     p[i++] = temp_to;
107                     p[i++] = temp_from;
108                 }
109                 j++;
110                 flag = true;
111             }
112             else
113             {
114                 if(to > from)
115                 {
116                     p[i++] = temp_to;
117                     p[i++] = temp_from;
118                 }
119                 j++;
120             }
121         }
122     }
123     memcpy(s, p, sizeof(p));
124     return;
125 }
126 
127 bool Traverse()
128 {
129     memset(visit, false, sizeof(visit));
130     visit[start] = true;
131     st[start] = 0;
132     Status init;
133     memcpy(init.value, input, sizeof(input));
134     queuing.push(init);
135     while(!queuing.empty())
136     {
137         Status ss = queuing.front();
138         State& s = ss.value;
139         int elem = try_to_insert(s);
140         queuing.pop();
141         //两个for循环加上两种插入的情况
142         for(int i=0; i<SIZE; ++i)
143         {
144             for(int j=0; j<SIZE; ++j)
145             {
146                 if(isExchange(s[i], s[j]))
147                 {
148                     Status tt;
149                     State& t = tt.value;
150                     for(int z=0; z<2; ++z)
151                     {
152                         memcpy(t, s, sizeof(t));
153                         if(i+dir[z] != j)
154                         {
155                             Translate(t, i, j, dir[z]);
156                             int step = try_to_insert(t);
157                             if(!visit[step])
158                             {
159                                 visit[step] = true;
160                                 st[step] = st[elem]+1;
161                                 queuing.push(tt);
162                                 if(step == 0)
163                                 {//step == 0 表示到达了已排序的状态则返回
164                                     return true;
165                                 }
166                             }
167                         }
168                     }
169                 }
170             }
171         }
172     }
173     return false;
174 }
175 
176 int main()
177  {
178      #ifndef ONLINE_JUDGE
179      freopen("F:\\test\\input.txt", "r", stdin);
180      #endif
181       getPrime();
182       int T = 0;
183      while(cin>>input[0] && input[0])
184      {
185          int flag = 0;
186          if(input[0] > 0)  flag++;
187 
188         for(int i=1; i<SIZE; ++i)
189         {
190             cin>>input[i];
191             if(input[i] > 0) flag++;
192         }
193         start = try_to_insert(input);
194         cout<<"Case "<<++T<<": ";
195         if (start == 0)
196         {
197             cout<<"0"<<endl;
198             continue;
199         }
200         if (flag == SIZE || !flag)
201         {
202             cout<<"-1"<<endl;
203             continue;
204         }
205         if(Traverse()) cout<<st[0]<<endl;
206         else cout<<"-1"<<endl;
207 
208         while(!queuing.empty()) queuing.pop();
209      }
210      return 0;
211  }

 

 

posted @ 2013-07-03 08:56  Gifur  阅读(403)  评论(0编辑  收藏  举报
TOP