Description
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 x
where the only legal operation is to exchange 'x' with one of the tiles with which it shares an edge. As an example, the following sequence of moves solves a slightly scrambled puzzle:
1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 5 6 7 8 5 6 7 8 5 6 7 8 5 6 7 8 9 x 10 12 9 10 x 12 9 10 11 12 9 10 11 12 13 14 11 15 13 14 11 15 13 14 x 15 13 14 15 x r-> d-> r->
The letters in the previous row indicate which neighbor of the 'x' tile is swapped with the 'x' tile at each step; legal values are 'r','l','u' and 'd', for right, left, up, and down, respectively.
Not all puzzles can be solved; in 1870, a man named Sam Loyd was famous for distributing an unsolvable version of the puzzle, and
frustrating many people. In fact, all you have to do to make a regular puzzle into an unsolvable one is to swap two tiles (not counting the missing 'x' tile, of course).
In this problem, you will write a program for solving the less well-known 8-puzzle, composed of tiles on a three by three
arrangement.
Input
1 2 3 x 4 6 7 5 8
is described by this list:
1 2 3 x 4 6 7 5 8
Output
Sample Input
2 3 4 1 5 x 7 6 8
Sample Output
ullddrurdllurdruldr
第一题典型八数码,然而由于开始写的string+map,超时n次,然后后来手动hash,又因为各种脑抽调试了n久,并且后来才发现是求路径而不是最小次数,但经过各种努力终于还是AC了QAQ,
思路倒是挺简单的,直接BFS,hash方式一般都用的康托展开,阶乘预处理下就好了,然后就是hash时把二维转成一维,扩展时把一维转成二维,这个也比较简单。。至于其他的就是一般的BFS过程了。。输出路径我是直接从终点往起点搜,这样就记录前驱直接输出,不用在递归或是重新记录。。
#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int MAX=1000000;
int sr[9],po;
int fan[9]={1,1,2,6,24,120,720,5040,40320};
bool visit[MAX];
char path[MAX];
int pre[MAX];
struct lmx{
int a[9];
int pos;
};
lmx s,t,h;
int temp = 0;
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
char st[5]="durl";
int str;
int kgto(int *m,int n)
{
int i,j,num,s=0;
for(i=0;i<n-1;i++)
{
num=0;
for(j=i+1;j<n;j++)
{
if(m[j]<m[i]) num++;
}
s+=num*fan[8-i];
}
return s;
}
int bfs()
{
memset(visit,false,sizeof(visit));
int i,val,x,y,xx,yy;
queue<lmx>q;
for(i=0;i<8;i++)//倒着搜方便输出
{
s.a[i]=i+1;
}
s.a[8]=0;
s.pos=8;
q.push(s);
val=kgto(s.a,9);
str = val;
visit[val]=true;
while(!q.empty())
{
h=q.front();
q.pop();
x=h.pos/3;
y=h.pos%3;
int id = kgto(h.a,9);
for(i=0;i<4;i++)
{
xx=x+dir[i][0];
yy=y+dir[i][1];
if(xx>=0&&xx<3&&yy>=0&&yy<3)
{
t=h;
swap(t.a[h.pos],t.a[xx*3+yy]);
t.pos=3*xx+yy;
val=kgto(t.a,9);
if(visit[val]==false)
{
visit[val]=true;
pre[val] = id;
path[val] = st[i];
q.push(t);
if(val == temp)return 1;
}
}
}
}
}
int main()
{
char ch[105];
int i;
while(gets(ch))
{
int count = 0;
for(int i = 0; i < strlen(ch); ++i){
if(ch[i] >= '0' && ch[i] <= '9')sr[count] = ch[i] - '0',po = count++;
else if(ch[i] == 'x')sr[count] = 0,po = count++;
}
temp=kgto(sr,9);
bfs();
if(visit[temp]==false) puts("unsolvable");
else{
int id = temp;
while(id != str){
printf("%c",path[id]);
id = pre[id];
}
}
}
return 0;
}
这是我写的
以下是另一种
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using std::queue;
const int dx[] = {0, 0, 1, -1};
const int dy[] = {1, -1, 0, 0};
const char dir[] = {'r', 'l', 'd', 'u'};
const int fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800};
int n = 9;
struct Node{
int a[10], status, pos;
int step, now;
void Get()
{
status = 0;
for(int i = 0; i < n; i++)
{
int t = 0;
for(int j = i + 1; j < n; j++)
if(a[j] < a[i]) t++;
status += t * fac[n-i-1];
}
}
}S, T;
bool hash[3628800+100];
queue<Node> Q;
int path[3628800+100], CNT = 0;
int pre[3628800+100];
bool expand(Node &nd, Node tmp, int k)
{
nd = tmp;
path[++CNT] = k; nd.now = CNT; pre[CNT] = tmp.now;
int x = tmp.pos / 3;
int y = tmp.pos % 3;
int nx = x + dx[k];
int ny = y + dy[k];
if(nx < 0 || nx > 2) return 0;
if(ny < 0 || ny > 2) return 0;
int npos = nx * 3 + ny;
std::swap(nd.a[nd.pos], nd.a[npos]);
nd.pos = npos; nd.Get();
return 1;
}
void PRINT(Node now)
{
for(int i = 0; i < 9; i++)
{
printf("%d ", now.a[i]);
if((i+1) % 3 == 0) puts("");
}
printf("%d\n\n", now.status);
}
void writeans(int now)
{
if(pre[now] == -1) return;
writeans(pre[now]);
puts("");
putchar(dir[path[now]]);
}
void BFS()
{
memset(pre, -1, sizeof(pre));
Q.push(S); hash[S.status] = 1; S.now = -1;
while(!Q.empty())
{
Node now = Q.front(); Q.pop();
if(now.step > 100) break;
if(now.status == T.status)
{
//PRINT(now);
writeans(now.now);
return;
}
//PRINT(now);
Node nd;
for(int k = 0; k < 4; k++)
{
if(!expand(nd, now, k)) continue;
if(!hash[nd.status])
{
hash[nd.status] = 1;
Q.push(nd);
}
}
}
puts("unsolvable");
}
int main()
{
//freopen("A.out", "w", stdout);
for(int i = 0; i < n; i++)
{
char ch; scanf(" %c", &ch);
if(ch == 'x')
{
S.a[i] = 0;
S.pos = i;
}
else S.a[i] = ch - '0';
}
S.Get(); S.step = 0;
for(int i = 0; i < n-1; i++) T.a[i] = i+1;
T.a[n-1] = 0; T.Get();
BFS();
return 0;
}
Description
At the beginning, the two dices may face different(which means there exist some i, a i ≠ b i). Ddy wants to make the two dices look the same from all directions(which means for all i, a i = b i) only by the following four rotation operations.(Please read the picture for more information)
Now Ddy wants to calculate the minimal steps that he has to take to achieve his goal.
Input
For each case, the first line consists of six integers a 1,a 2,a 3,a 4,a 5,a 6, representing the numbers on dice A.
The second line consists of six integers b 1,b 2,b 3,b 4,b 5,b 6, representing the numbers on dice B.
Output
Sample Input
1 2 3 4 5 6 1 2 3 4 5 6 1 2 3 4 5 6 1 2 5 6 4 3 1 2 3 4 5 6 1 4 2 5 3 6
Sample Output
0 3 -1
这个是WA
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
struct node{
int s[6];
int cnt;
}st,ed;
char s[20];
bool flag = false;
int ans = -1;
int edHash = 0;
bool Hash[850000];
int getHash(int *a){
int t = 1;
for(int i = 0; i < 6; ++i)
t = t * 7 + a[i];
return t;
}
bool check(node n)
{
int id = getHash(n.s);
if(Hash[id])return false;
Hash[id] = 1;
if(edHash == id)flag = true;
return true;
}
node expand(node n,int i)
{
switch(i){
case 0 :{
swap(n.s[0],n.s[2]);
swap(n.s[1],n.s[3]);
swap(n.s[0],n.s[1]);
break;
}
case 1 :{
swap(n.s[0],n.s[2]);
swap(n.s[1],n.s[3]);
swap(n.s[2],n.s[3]);
break;
}
case 2 :{
swap(n.s[0],n.s[4]);
swap(n.s[1],n.s[5]);
swap(n.s[0],n.s[1]);
break;
}
case 3 :{
swap(n.s[0],n.s[4]);
swap(n.s[1],n.s[5]);
swap(n.s[4],n.s[5]);
break;
}
}
n.cnt++;
return n;
}
bool bfs()
{
queue<node>q;
q.push(st);
node nd,xd;
int stHash = getHash(st.s);
if(stHash == edHash)return 1;
while(q.size()){
nd = q.front();q.pop();
for(int i = 0; i < 4; ++i){
xd = expand(nd,i);
if(check(xd)){
q.push(xd);
if(flag){
ans = xd.cnt;
return 1;
}
}
}
}
return 0;
}
int main()
{
while(gets(s)){
flag = false;
ans = -1;
memset(Hash,0,sizeof(Hash));
int count = 0;
for(int i = 0; i < strlen(s); ++i){
if(s[i] >= '0' && s[i] <= '9')st.s[count++] = s[i] - '0';
}
gets(s);
count = 0;
for(int i = 0; i < strlen(s); ++i){
if(s[i] >= '0' && s[i] <= '9')ed.s[count++] = s[i] - '0';
}
Hash[getHash(st.s)] = 1;
st.cnt = 0;
edHash = getHash(ed.s);
if(bfs())printf("%d\n",ans == -1 ? 0 : ans);
else printf("%d\n",-1);
}
return 0;
}
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
struct node
{
int s1,s2,s3,s4,s5,s6;
int sum;
} q[800000];
int a[7],b[7];
int c[7][7][7][7][7][7];
void bfs()
{
memset(c,0,sizeof(c));
struct node t,r;
t.s1=b[1];
t.s2=b[2];
t.s3=b[3];
t.s4=b[4];
t.s5=b[5];
t.s6=b[6];
t.sum=0;
int k=0,l=0;
q[l++]=t;
while(k<l)
{
t=q[k++];
if(t.s1==a[1] && t.s2==a[2] && t.s3==a[3] && t.s4==a[4] && t.s5==a[5] && t.s6==a[6])
{
printf("%d\n",t.sum);
return ;
}
for(int i=0; i<4; i++)
{
if(i==0)
{
r.s1=t.s4;
r.s2=t.s3;
r.s3=t.s1;
r.s4=t.s2;
r.s5=t.s5;
r.s6=t.s6;
}
else if(i==1)
{
r.s1=t.s3;
r.s2=t.s4;
r.s3=t.s2;
r.s4=t.s1;
r.s5=t.s5;
r.s6=t.s6;
}
else if(i==2)
{
r.s1=t.s5;
r.s2=t.s6;
r.s3=t.s3;
r.s4=t.s4;
r.s5=t.s2;
r.s6=t.s1;
}
else
{
r.s1=t.s6;
r.s2=t.s5;
r.s3=t.s3;
r.s4=t.s4;
r.s5=t.s1;
r.s6=t.s2;
}
if(!c[r.s1][r.s2][r.s3][r.s4][r.s5][r.s6])
{
c[r.s1][r.s2][r.s3][r.s4][r.s5][r.s6]=1;
r.sum=t.sum+1;
q[l++]=r;
}
}
}
printf("-1\n");
}
int main()
{
while(~scanf("%d",&a[1]))
{
for(int i=2; i<=6; i++)
scanf("%d",&a[i]);
for(int i=1; i<=6; i++)
scanf("%d",&b[i]);
bfs();
}
return 0;
}
这个AC
第三题:UVAlive 6470:
此题很明显是个博弈,所以两人都很聪明
我们可以用记忆化搜索,设f[x][y][z]是到x,y,z这个状态的时候会输还是会赢,有我们等会的思路,可知无论是什么样的巧克力,到这步状态的x,y,z输赢不会变;
我们就枚举吃哪块巧克力,注意用到一个博弈的思想:当前扩展出的所有下一状态必输,那么当前才必赢。这个很重要
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int f[105][105][105];
int T;
bool is_win(int x,int y,int z){
if(x == 1 && y == 0 && z == 0)return 1;
if(f[x][y][z] != -1)return f[x][y][z];
bool flag = 1;
for(int i = 2; i <= x; ++i){
int xx = i - 1, yy = y, zz = z;
yy = min(xx,yy);
zz = min(zz,xx);//吃掉巧克力的状态,下同
if(is_win(xx,yy,zz))flag = 0;//如果下一次赢了,那此次必输,下同
}
for(int i = 1; i <= y; ++i){
int xx = x, yy = i - 1, zz = z;
zz = min(zz,yy);
if(is_win(xx,yy,zz))flag = 0;
}
for(int i = 1; i <= z; ++i){
int xx = x, yy = y, zz = i - 1;
if(is_win(xx,yy,zz))flag = 0;
}
return f[x][y][z] = flag;
}
void sovle()
{
int p,q,r;
scanf("%d%d%d",&p,&q,&r);
for(int i = 2; i <= p; ++i){
int xx = i - 1, yy = q, zz = r;
yy = min(xx,yy);
zz = min(zz,xx);//吃掉巧克力后的状态,下同
if(is_win(xx,yy,zz)){
printf("W %d 1\n",i);
return ;
}
}
for(int i = 1; i <= q; ++i){
int xx = p, yy = i - 1, zz = r;
zz = min(zz,yy);
if(is_win(xx,yy,zz)){
printf("W %d 2\n",i);
return ;
}
}
for(int i = 1; i <= r; ++i){
int xx = p,yy = q, zz = i - 1;
if(is_win(xx,yy,zz)){
printf("W %d 3\n",i);
return ;
}
}
printf("L\n");
}
int main()
{
scanf("%d",&T);
memset(f,-1,sizeof(f));
while(T--){
int k;
scanf("%d",&k);
printf("%d ",k);
sovle();
}
return 0;
}
Description
Thanks a lot for helping Harry Potter in finding the Sorcerer's Stone of Immortality in October. Did we not tell you that it was just an online game ? uhhh! now here is the real onsite task for Harry. You are given a magrid S ( a magic grid ) having R rows and C columns. Each cell in this magrid has either a Hungarian horntail dragon that our intrepid hero has to defeat, or a flask of magic potion that his teacher Snape has left for him. A dragon at a cell (i,j) takes away |S[i][j]| strength points from him, and a potion at a cell (i,j) increases Harry's strength by S[i][j]. If his strength drops to 0 or less at any point during his journey, Harry dies, and no magical stone can revive him.
Harry starts from the top-left corner cell (1,1) and the Sorcerer's Stone is in the bottom-right corner cell (R,C). From a cell (i,j), Harry can only move either one cell down or right i.e., to cell (i+1,j) or cell (i,j+1) and he can not move outside the magrid. Harry has used magic before starting his journey to determine which cell contains what, but lacks the basic simple mathematical skill to determine what minimum strength he needs to start with to collect the Sorcerer's Stone. Please help him once again.
Input (STDIN):
The first line contains the number of test cases T. T cases follow. Each test case consists of R C in the first line followed by the description of the grid in R lines, each containing C integers. Rows are numbered 1 to R from top to bottom and columns are numbered 1 to C from left to right. Cells with S[i][j] < 0 contain dragons, others contain magic potions.
Output (STDOUT):
Output T lines, one for each case containing the minimum strength Harry should start with from the cell (1,1) to have a positive strength through out his journey to the cell (R,C).
Constraints:
1 ≤ T ≤ 5
2 ≤ R, C ≤ 500
-10^3 ≤ S[i][j] ≤ 10^3
S[1][1] = S[R][C] = 0
Sample Input:
3
2 3
0 1 -3
1 -2 0
2 2
0 1
2 0
3 4
0 -2 -3 1
-1 4 0 -2
1 -2 -3 0
Sample Output:
2
1
2
Explanation:
Case 1 : If Harry starts with strength = 1 at cell (1,1), he cannot maintain a positive strength in any possible path. He needs at least strength = 2 initially.
Case 2 : Note that to start from (1,1) he needs at least strength = 1.
Hint
Added by: | Varun Jalan |
Date: | 2011-12-15 |
Time limit: | 0.336s |
Source limit: | 50000B |
Memory limit: | 1536MB |
Cluster: | Cube (Intel Pentium G860 3GHz) |
Languages: | All |
Resource: | Anil Kishore - ICPC Asia regionals, Amritapuri 2011 |
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int T;
int map[500 + 5][500 + 5];
int R,C;
int f[500 + 5][500 + 5];
bool check(int st)
{
memset(f,0,sizeof(f));
f[1][1] = st;
for(int i = 1; i <= R; ++i){
for(int j = 1; j <= C; ++j){
if(f[i][j])continue;
if(f[i - 1][j] > 0 && f[i][j - 1] > 0)
f[i][j] = max(f[i - 1][j], f[i][j - 1]) + map[i][j];
else if(f[i - 1][j] > 0)f[i][j] = f[i - 1][j] + map[i][j];
else if(f[i][j - 1] > 0)f[i][j] = f[i][j - 1] + map[i][j];
else f[i][j] = -0x3f3f3f3f;
}
}
if(f[R][C] > 0)return 1;
else return 0;
}
int main()
{
scanf("%d",&T);
while(T--){
scanf("%d%d",&R, &C);
int l = 0,r = 250000000;
for(int i = 1; i <= R; ++i){
for(int j = 1; j <= C; ++j)
{
scanf("%d",&map[i][j]);
}
}
while(l < r){
int m = (l + r) >> 1;
if(check(m))r = m;
else l = m + 1;
}
printf("%d\n",l);
}
return 0;
}
总之,这几道题思路还是比较简单,但是写的时候调试了好久,代码水平有待提高,加油!!