【noip停课集训,10.12】【#2training】

POJ 1077
A - Eight(据说此题不做人生就不完整)
Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

Description

The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one tile missing. Let's call the missing tile 'x'; the object of the puzzle is to arrange the tiles so that they are ordered as: 
 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

You will receive a description of a configuration of the 8 puzzle. The description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and the tiles listed from left to right within a row, where the tiles are represented by numbers 1 to 8, plus 'x'. For example, this puzzle 
 1  2  3 
 x  4  6 
 7  5  8 

is described by this list: 
 1 2 3 x 4 6 7 5 8 

Output

You will print to standard output either the word ``unsolvable'', if the puzzle has no solution, or a string consisting entirely of the letters 'r', 'l', 'u' and 'd' that describes a series of moves that produce a solution. The string should include no spaces and start at the beginning of the line.

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;
}

HDU5012
B - Dice
Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

Description

There are 2 special dices on the table. On each face of the dice, a distinct number was written. Consider a  1.a  2,a  3,a  4,a  5,a  6 to be numbers written on top face, bottom face, left face, right face, front face and back face of dice A. Similarly, consider b  1.b  2,b  3,b  4,b  5,b 6 to be numbers on specific faces of dice B. It’s guaranteed that all numbers written on dices are integers no smaller than 1 and no more than 6 while a  i ≠ a  j and b  i ≠ b  j for all i ≠ j. Specially, sum of numbers on opposite faces may not be 7. 

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

There are multiple test cases. Please process till EOF. 

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

For each test case, print a line with a number representing the answer. If there’s no way to make two dices exactly the same, output -1.
 

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
 
此题巨水,hash随便乱搞,状态我是四种情况直接换,但是我写了两份,一份能过,一份不能过,但是自己对拍全过,就郁闷了。。。

这个是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;
}

SPOJ AMR11A
D - Magic Grid
Time Limit:336MS     Memory Limit:1572864KB     64bit IO Format:%lld & %llu

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.

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;
}
总之,这几道题思路还是比较简单,但是写的时候调试了好久,代码水平有待提高,加油!!

























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值