很遗憾,刚刚开始做OJ,南开大学的网站就挂了,难道老天看不惯我搞这个,有木有。???
不过北大依然刚硬,遂在北大随便找了道题如下:
Robots(机器人) http://poj.org/problem?id=1098
说明:
机器人游戏是一个在31x31棋盘上玩的单人游戏,棋盘被分割为1x1的单元并按31行31列排列,每一个单元被索引为(r,c),r代表行号,c代表列号(从1开始),单元有四种状态:1.空,2.被你占领 3.被机器人占领,4.被碎片占领。游戏的目标是按照一定的路径行动,在机器人摧毁你之前把所有的机器人摧毁。
初始状态,你占领 单元(15,15),并且棋盘上有R个机器人,(1<=R<=50),他们分布在不同于(15,15)的单元,其他单元为空。你还被给予了一张T(0<=T<=20)个单元的列表,这些单元的含有传送门。你先移动,然后是机器人,然后再是你。在你移动的过程中,你可以移动到相邻的八个罗盘方向的任意为空的单元,或者移动到传送门列表上的任意一个单元,或者静止不动。另外,你也可以移动到相邻的含有碎片的单元,但必须顺着你移动的路线,把碎片推到下一个相邻的不含碎片的单元。如果碎片被推到一个含有机器人的单元,那机器人就被摧毁。如果你选择传送,那么目的地址必须是个空单元。你不能进行任何会把你自己或碎片移出棋局的移动。
机器人移动时,每个机器人移动离你最近的到相邻单元(可以不为空),单元与单元的距离通过|r1-r2| +|c1-c2|计算 ,当两个机器人移动到相同单元或者移动到含有碎片的单元,机器人被摧毁。当任一机器人移动到你的当前位置时,你输掉游戏。如果两个机器人同时移动到你所在的位置,虽然机器人被摧毁,但是你依然输掉游戏,游戏结束。当所有的机器人都被摧毁,并且没有机器人移动到你的位置,你赢得游戏。
为了尽可能长的进行游戏,你可以仅考虑进行不会马上输掉的移动,一种貌似有理的策略是:总是保持不动或者进行移动之后,棋盘上剩余的机器人最少或者移动的最小。在两种移动相同下无法决定的情况下,选择离当前所有机器人最远的移动,如果还是无法决定,选择行号最小的单元移动,再无法决定,选择列号最小的单元移动。
如果任何一个移动或者保持都会导致游戏结束,你可以选择传送到列表上的任意一个合法的地方。当进行传送位置搜索时,你每次都应该从列表头开始查找。如果没有任何一个地方可以传送,你只能保持不动,并且输掉游戏。在这个问题中,你将执行这种游戏策略,并且看看它是否能有效工作。
输入:
输入包含一系列的实例,每一个实例的第一行包含两个空格分隔的数字R,T ,然后紧跟着R行,每一行含有两个数字标识出R个机器人的初始位置。你可以假设每一个机器人占领一个除(15,15)外的不同单元,接下来的T行给出了传送门的位置,每一号包含一个行号和列号,当遇到(0,0)时,输入结束。
输出:
1.在每一个用例中,按照示例输出的格式 打印出用例号(从1开始).
2.每次传送时,按以下格式打印一行:
Move m: teleport to (r, c)
m 等于至传送时你执行的移动的个数(包括本次), (r,c)是你传送的单元地址。
3.如果你赢得游戏,打印以下3行:
Won game after making m moves.
Final position (r,c)
Number of cells with debris: d
如果你输掉游戏,打印以下4行:
Lost game after making m moves.
Final position: (r,c)Number of cells with debris: d
Number of robots remaining: n
示例输入:
4 0
17 18
13 18
8 12
10 12
4 0
17 17
13 17
13 13
17 13
3 3
17 18
13 18
5 31
15 16
16 15
3 7
0 0
示例输出:
Case 1:
Won game after making 5 moves.
Final position: (14,16)
Number of cells with debris: 1
Case 2:
Lost game after making 2 moves.
Final position: (15,15)
Number of cells with debris: 1
Number of robots remaining: 0
Case 3:
Move 30: teleport to (16,15)
Move 58: teleport to (15,16)
Move 86: teleport to (3,7)
Lost game after making 114 moves.
Final position: (1,29)
Number of cells with debris: 1
Number of robots remaining: 1
解题思路:每一次移动都枚举出各种移动方法,选择最优的进行移动。
可做了一天依然没有AC,只有先放在这里了:
#include<iostream>
#include<list>
#include<algorithm>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<map>
#include<utility>
using namespace std;
struct postion
{
friend ostream &operator<<(ostream & os, postion &pos);
postion(){}
postion(int _x,int _y):x(_x),y(_y ) {}
int x;
int y;
bool operator==(const postion &pos) const;
bool operator<(const postion &pos) const;
postion &operator=(const postion &pos);
};
bool postion::operator==(const postion &pos) const
{
if(this->x==pos.x && this->y==pos.y )
return true;
else
return false;
}
bool postion::operator<(const postion &pos) const
{
return ( x<pos.x || ( (x==pos.x)? (y<pos.y) :false) );
}
postion &postion::operator=(const postion &pos)
{
this->x=pos.x;
this->y=pos.y;
return *this;
}
ostream &operator<<(ostream & os, postion &pos)
{
os<<"("<<pos.x<<","<<pos.y<<")";
return os;
}
#define POS_EMPTY 0
#define POS_ROBOT 1
#define POS_DEBRIS -1
#define POS_PLAYER -2
#define BROAD_NUM 32
#define Is_Valid_Pos(i,j) (((i)>0 && (i)< BROAD_NUM) && ((j) >0 && (j) < BROAD_NUM) )
#define DISTANT(Px,Py) ( abs( (Px).x-(Py).x ) + abs( (Px).y -(Py).y ) )
class Game
{
public:
Game();
Game(const Game &game);
struct Is_Debris;
struct Is_Danger;
struct Is_Safe;
list<postion> robots;
list<postion> debris;
list<postion> teleport;
int broad[BROAD_NUM][BROAD_NUM];
postion player;
//一切初始化
void Init();
//生成pos邻近的9个点坐标
list<postion> Compass(const postion &pos) const;
list<postion> Location(const postion &pos) ;
//是否能移动到新位置
bool MoveCan(const postion &pos) const;
//查找离robot离 player 最近的点
postion Closest( const postion &robot, const postion &player) const;
int Destory(list<postion> &p_list) ;
void Destant();
void Move();
void Input(istream &in,int R, int T);
bool IsSafe(const postion &pos) const;
bool operator<(const Game &) const;
Game &operator=(const Game & game);
private:
//计算列表中的重复值数目
int Repeat(list<postion> &p_list) ;
int Debris(list<postion> &p_list) ;
int worth;
int distant;
int move;
};
struct Game::Is_Debris
{
public:
Is_Debris(const Game *_game);
bool operator()(const postion &pos ) const;
static int count;
private:
const Game *game;
};
int Game::Is_Debris::count=0;
Game::Is_Debris::Is_Debris(const Game *_game):game(_game){}
bool Game::Is_Debris::operator()(const postion &pos ) const
{
if(game->broad[ pos.x ][ pos.y] == POS_DEBRIS )
{
count+=1;
return true;
}
return false;
}
struct Game::Is_Danger
{
public:
Is_Danger(const Game *_game);
bool operator()(const postion &pos ) const;
private:
const Game *game;
};
Game::Is_Danger::Is_Danger(const Game *_game):game(_game){}
bool Game::Is_Danger::operator()(const postion &pos ) const
{
if(game->broad[pos.x][pos.y] ==POS_DEBRIS )
return false;
return !game->IsSafe(pos);
}
struct Game::Is_Safe
{
public:
Is_Safe(const Game *_game);
bool operator()(const postion &pos ) const;
private:
const Game *game;
};
Game::Is_Safe::Is_Safe(const Game *_game):game(_game){}
bool Game::Is_Safe::operator()(const postion &pos ) const
{
return game->IsSafe(pos) && game->broad[pos.x][pos.y]==POS_EMPTY;
}
void Game::Init()
{
memset(broad,0,sizeof(int) *BROAD_NUM * BROAD_NUM );
robots.clear();
debris.clear();
teleport.clear();
player.x=player.y=15;
broad[15][15]=POS_PLAYER;
worth=0;
distant=0;
move=0;
}
list<postion> Game::Compass(const postion &pos) const
{
list<postion> p_list;
for(int i=pos.x-1; i<=pos.x+1 ;i++ )
{
for(int j=pos.y-1 ; j <= pos.y+1 ; j++ )
{
if( ! Is_Valid_Pos(i,j) )
continue;
p_list.push_back( postion(i,j) );
}
}
return p_list;
}
list<postion> Game::Location(const postion &pos)
{
list<postion> p_list=Compass(pos);
list<postion>::iterator iter=remove_if(p_list.begin(), p_list.end() ,
Game::Is_Danger(this) );
p_list.erase(iter,p_list.end() );
bool status=false;
for(list<postion>::iterator iter=p_list.begin();iter!=p_list.end();
iter++)
{
if( broad[iter->x][iter->y] ==POS_DEBRIS )
{
int x,y;
x= iter->x-(player.x-iter->x );
y= iter->y-(player.y-iter->y);
if( Is_Valid_Pos(x,y) )
{
status=true;
break;
}
}
else
{
status=true;
break;
}
}
if (status==false)
{
list<postion>::iterator iter=
find_if(teleport.begin(),teleport.end(),Game::Is_Safe(this) );
if (iter!=teleport.end())
p_list.push_back(*iter);
}
if (p_list.size()==0)
{
p_list.push_back(player);
}
return p_list;
}
/*
list<postion> Game::Location(const postion &pos)
{
list<postion> p_list=Compass(pos);
list<postion>::iterator iter=remove_if(p_list.begin(), p_list.end() ,
Game::Is_Danger(this) );
p_list.erase(iter,p_list.end() );
bool status=false;
for(list<postion>::iterator iter=p_list.begin();iter!=p_list.end();
iter++)
{
if( broad[iter->x][iter->y] ==POS_DEBRIS )
{
int x,y;
x= iter->x-(player.x-iter->x );
y= iter->y-(player.y-iter->y);
if( Is_Valid_Pos(x,y) )
{
status=true;
break;
}
}
else
{
status=true;
break;
}
}
if (status==false)
{
list<postion>::iterator iter=
find_if(teleport.begin(),teleport.end(),Game::Is_Safe(this) );
if (iter!=teleport.end())
p_list.push_back(*iter);
}
if (p_list.size()==0)
{
p_list.push_back(player);
}
return p_list;
}
*/
postion Game::Closest( const postion &robot, const postion &player) const
{
int closest=70;
list<postion> p_list=Compass( robot );
postion ret_pos;
for(list<postion>::const_iterator iter=p_list.begin();
iter!=p_list.end() ;iter++ )
{
int distance=DISTANT( *iter , player );
if( distance < closest )
{
closest=distance;
ret_pos=*iter;
}
}
return ret_pos;
}
int Game::Debris(list<postion> &p_list)
{
Game::Is_Debris::count=0;
list<postion>::iterator iter=
remove_if( p_list.begin(), p_list.end(), Game::Is_Debris( this ) );
p_list.erase(iter,p_list.end() );
return Game::Is_Debris::count;
}
int Game::Repeat(list<postion> &p_list)
{
map<postion,int> hash;
for(list<postion>::const_iterator iter=p_list.begin();
iter!=p_list.end();iter++)
{
map<postion,int>::iterator it=hash.find( *iter );
if( it != hash.end() )
hash[*iter]++;
else
hash[*iter]=1;
}
p_list.unique();
int sum=0;
for( map<postion,int>::iterator iter=hash.begin();
iter!=hash.end( );iter++ )
{
if( iter->second > 1 )
{
sum+=iter->second;
broad[iter->first.x ][ iter->first.y ]=POS_DEBRIS;
debris.push_back( iter->first );
p_list.remove(iter->first);
}
}
return sum;
}
int Game::Destory(list<postion> & p_list)
{
int value=0;
value+=Repeat(p_list);
value+=Debris(p_list);
for (list<postion>::iterator iter=robots.begin();
iter!=robots.end();iter++)
broad[iter->x][iter->y]=POS_EMPTY;
for (list<postion>::iterator iter=p_list.begin();
iter!=p_list.end();iter++)
broad[iter->x][iter->y]=POS_ROBOT;
return value;
}
void Game::Destant()
{
int tmp;
distant=100;
for(list<postion>::iterator iter=robots.begin();
iter!=robots.end() ;iter++)
{
tmp=DISTANT( *iter,player);
if( tmp<distant )
distant=tmp;
}
}
/*
compass:生成可以移动到得位置列表:包括传送。
*/
void Game::Move()
{
int time=0;
bool win=true;
while( robots.size()!=0 )
{
if (broad[player.x][player.y]!=POS_PLAYER )
{
win=false;
break;
}
time+=1;
#ifdef DEBUG
cout<<"move "<< (time) <<endl;
cout<<"player("<<player.x<<","<<player.y<<")"<<endl;
#endif
if (time==113)
{
time++;
time--;
}
list<postion> location=Location(player);
list<Game> g_list;
for(list<postion>::const_iterator iter=location.begin();
iter!=location.end(); ++iter )
{
Game g(*this);
int worth=0;
if ( DISTANT( (*iter) , player ) >2 )
{
cout<<"Move "<<time<<": teleport to ("<< iter->x<<","<<iter->y<<")"<<endl;
}
else if( g.broad[iter->x][iter->y] ==POS_DEBRIS )
{
int x,y;
x= iter->x-(g.player.x-iter->x );
y= iter->y-(g.player.y-iter->y);
if( !Is_Valid_Pos(x,y) )
continue;
g.debris.remove( *iter );
g.debris.push_back( postion(x,y) );
if(g.broad[x][y]==POS_ROBOT)
{
worth+=1;
g.robots.remove( postion(x,y) ); //destory a robot.
}
g.broad[x][y]=POS_DEBRIS;
}
g.broad[player.x][player.y]=POS_EMPTY;
g.broad[iter->x][iter->y]=POS_PLAYER;
g.player=*iter;
int r_move=0;
list<postion> np_list;
for(list<postion>::iterator r_iter=g.robots.begin();
r_iter!=g.robots.end() ;r_iter++ )
{
postion closet=g.Closest(*r_iter, g.player );
np_list.push_back( closet );
r_move+=DISTANT(*r_iter, closet );
}
move=r_move;
worth+=g.Destory(np_list);
g.worth=worth;
g.robots=np_list;
g.Destant();
g_list.push_back(g);
}
#ifdef DEBUG
for (list<Game>::iterator iter=g_list.begin();iter!=g_list.end();iter++)
{
/* cout<<" player:"<<iter->player
<<" distant:"<<iter->distant
<<" worth:"<<iter->worth
<<" robots:"<<iter->robots.size()
<<" debris:"<<iter->debris.size()<<" ";*/
for (list<postion>::iterator p_iter=iter->debris.begin();
p_iter!=iter->debris.end();p_iter++ )
{
cout<<"debris:"<<*p_iter<<endl;
}
for (list<postion>::iterator p_iter=iter->robots.begin();
p_iter!=iter->robots.end();p_iter++ )
{
cout<<"robots:"<<*p_iter<<endl;
}
cout<<endl;
}
#endif
list<Game>::iterator iter=max_element( g_list.begin(),g_list.end() );
this->operator=(*iter);
this->worth=0;
this->distant=0;
}
if (broad[player.x][player.y]==POS_DEBRIS)
win=false;
if(win)
cout<<"Won game after making "<<time<<" moves."<<endl;
else
cout<<"Lost game after making "<<time-1<<" moves."<<endl;
cout<<"Final position: ("<<player.x<<","<<player.y<<") "<<endl;
cout<<"Number of cells with debris: "<<debris.size()<<endl;
if(!win)
cout<<"Number of robots remaining: "<<robots.size()<<endl;
cout<<endl;
}
bool Game::operator<(const Game &game) const
{
if(worth<game.worth )
return true;
else if (worth > game.worth)
return false;
if(distant<game.distant )
return true;
else if (distant > game.distant)
return false;
if(player.x > game.player.x)
return true;
else if(player.x < game.player.x)
return false;
if(player.y > game.player.y)
return true;
else if(player.y < game.player.y)
return false;
assert(0);
return false;
}
Game & Game::operator=(const Game & game)
{
memcpy(broad,game.broad, sizeof(int) *BROAD_NUM *BROAD_NUM );
robots=game.robots;
debris=game.debris;
teleport=game.teleport;
player=game.player;
worth=game.worth;
distant=game.distant;
return *this;
}
bool Game::IsSafe(const postion &pos) const
{
list<postion> p_list=Compass(pos);
for(list<postion>::iterator iter=p_list.begin();
iter!=p_list.end();
iter++)
{
if( broad[iter->x][iter->y]==POS_ROBOT )
return false;
}
return true;
}
Game::Game(const Game &game)
{
this->operator=(game);
}
Game::Game(){}
void Game::Input(istream &cin,int R,int T)
{
int r,c;
for(int i=0;i<R;i++)
{
cin>>r>>c;
assert( (r>0 && r< BROAD_NUM) && (c >0 &&c <BROAD_NUM) );
robots.push_back( postion(r,c) );
broad[r][c]=POS_ROBOT;
}
for(int i=0;i<T;i++)
{
cin>>r>>c;
assert( (r>0 && r<BROAD_NUM) && (c >0 &&c < BROAD_NUM) );
teleport.push_back( postion(r,c) );
}
}
#include <fstream>
int main()
{
int R,T;
Game game;
int Case=1;
ifstream in("input");
while(cin>>R>>T)
{
if(R==T&&R==0)
break;
cout<<"Case "<<Case<<endl;
game.Init();
game.Input(cin,R,T);
game.Move();
Case++;
}
}