1. 程式人生 > 其它 >執行緒池之FixedThreadPool

執行緒池之FixedThreadPool

技術標籤:hdu/poj

題目描述

在一個3*3的棋盤上放置編號為1-8的8個方塊,每個佔一格,另外還有一個空格。與空格相鄰的數字方塊可以移動到空格里。任務1:指定初始棋局和目標棋局,計算出最少的移動步數;任務2:輸出數碼的移動序列。
把空格看成0,一共有9個數字。
輸入樣例:

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

輸出樣例:

2

初始棋局和目標棋局

題目分析

這裡先解決任務1,任務2是在任務1的基礎上通過標記序列和回溯去解決的。
把一個棋局看成一個狀態圖,總共有9!= 362880個狀態。從初始棋局開始,每次移動轉到下一個狀態,到達目標棋局停止。八數碼問題其實是一個經典的BFS問題。八數碼從初始狀態出發,每次轉移逐步逼近目標狀態。每轉移一次,步數加1,當達到目標時,經過的步數就是最短路徑。

八數碼的重要問題其實是判重。對於已經訪問過的狀態要進行標記,防止重複訪問。這裡可以用數學方法“康託展開”來判重。
至於“康託展開”是什麼,可以參考以下部落格。
都能看懂的康託展開

程式碼:

#include<bits/stdc++.h>
using namespace std;
const int LEN=362880;
struct node{
	int state[9];//記錄一個八數碼排列,即一個狀態
	int dis;//記錄到起點的距離
};
int dir[4][2]={
	{-1,0},
	{0,-1},
	{1,0},
	{0,1}
};//左、上、右、下的順時針方向
int vis[
LEN]; int start[9],goal[9]; long int factory[]={1,1,2,6,24,120,720,5040,40320,362880};//0-9的階乘 //用康託展開判重 int Cantor(int str[],int n) { long result; for(int i=0;i<n;i++){ int count=0; for(int j=i+1;j<n;j++){ if(str[i]>str[j]) count++; } result+=count*factory[n-i-1]; } if(!vis[result]){ vis[
result]=1; return 1; } else return 0; } int bfs() { queue<node> Q; node head; head.dis=0; //複製起點的狀態 memcpy(head.state,start,sizeof(head.state)); if(Cantor(head.state,9)) Q.push(head); while(!Q.empty()){ head=Q.front(); //到達目標,返回距離 if(memcmp(head.state,goal,sizeof(goal))==0){ return head.dis; } Q.pop(); int z; //找到0的位置 for(z=0;z<9;z++){ if(head.state[z]==0){ break; } } int x,y; //橫、縱座標 x=z%3;y=z/3; for(int i=0;i<4;i++){ int newx,newy; newx=x+dir[i][0]; newy=y+dir[i][1]; //轉為一維 int nz=newy*3+newx; if(newx>=0&&newx<3&&newy>=0&&newy<3){//未越界 node newnode; memcpy(&newnode,&head,sizeof(struct node)); //把0移動到新的位置 swap(newnode.state[z],newnode.state[nz]); newnode.dis++; if(Cantor(newnode.state,9)){ Q.push(newnode); } } } } return -1;//沒找到 } int main() { for(int i=0;i<9;i++) cin>>start[i]; for(int i=0;i<9;i++) cin>>goal[i]; int num=bfs(); if(num!=-1) cout<<num<<endl; else cout<<"Impossible"<<endl; return 0; }

更多

關於任務2,輸出數碼的移動序列,也就是如何記錄移動過程的操作,如何記錄、回溯,可以參考以下部落格裡面的例題。
Eight