1、知识点:动态规划
2、思路:此题最大的难点恐怕还是表达式处理,我用的是栈,代码比较长,但注释比较详细。
/*
*/
#include <stdio.h>
#include <string.h>
#include <string>
#include <stack>
using namespace std;
#define MAXN 100+10 //N,M,K最大值
#define MAXEXPRELEN 250+10
struct Point{ //点
int x;
int y;
int dir; //标记到当前点的方向
};
Point fork_point[MAXN]; //分叉点
Point cur_poi; //当前点
struct Invert{ //定义转换点
int a;
int b;
char c[5];
};
Invert inv[MAXN]; //转换点
char sent[MAXEXPRELEN]; //表达式
int reg_arr[26+5]; //寄存器数组
int N, //field
M, //fork
K; //register-invert-point
int get_val(const char *formu); //计算表达式的值
int get_pri(string str); //获取优先级
bool is_fork(); //判断当前点是否分叉
void next_posi(int res, Point &poi); //根据当前点计算下一个位置
bool is_out(Point poi); //检查新点是否出界
bool is_invert(int ®); //检查当前点是否转换点,若是可得寄存器编号
int main()
{
memset(reg_arr, 0, sizeof(reg_arr));
gets(sent);
scanf("%d%d%d", &N, &M, &K);
for(int i=0; i<M; i++)
scanf("%d%d", &(fork_point[i].x), &(fork_point[i].y));
for(int j=0; j<K; j++)
scanf("%d%d%s", &(inv[j].a), &(inv[j].b), &(inv[j].c));
cur_poi.x = 1;
cur_poi.y = 0;
cur_poi.dir = 1; //(0,0)->(1,0):右
printf("%d %d\n", 0, 0);
printf("%d %d\n", 1, 0);
Point new_poi;
int inv_reg; //转换的寄存器编号
for(;;){
int res = -1; //默认直走
if(is_fork()) //如果站在分叉点
res = get_val(sent); //左,右?
if(is_invert(inv_reg)) //如果站在转换点
reg_arr[inv_reg] = 1 - reg_arr[inv_reg];
next_posi(res, new_poi); //计算下一个点
bool ch = is_out(new_poi); //检查新点是否出界
if(!ch){
printf("%d %d\n", new_poi.x, new_poi.y);
cur_poi.x = new_poi.x;
cur_poi.y = new_poi.y;
cur_poi.dir = new_poi.dir;
}
else
break;
}
return 0;
}
int get_val(const char *formu)
{
string expre = formu;
expre += "#";
int len = expre.length();
stack<string> sym;
stack<string> oper;
string str=""; //临时字符串
string top_str=""; //栈顶运算符
string top_oper=""; //栈顶操作数
int str_len=0;
sym.push("#");
for(int i=0; i<len; i++){
str += expre[i];
str_len++;
if(str == " "){ //如果是空格
str = "";
str_len = 0;
continue;
}
if(isalpha(str[0])){
int j;
for(j=i+1; j<len; j++)
if(isalpha(expre[j])){
str += expre[j];
str_len++;
}
else
break;
i = j-1; //其它字符,i移至最后一个有效字符
}
if( str=="TRUE" || str=="FALSE" ||
(isalpha(str[0]) && str_len == 1)) //寄存器或真值
oper.push(str);
else{ //操作符 或 括号
if(get_pri(str) > get_pri(sym.top()) ||
(sym.top()=="("&&str!=")") || str=="NOT")//>栈顶优先级 或 栈顶是左括号 或 "NOT"(NOT是右结合)
sym.push(str);
else if(sym.top()=="(" && str==")")
sym.pop();
else{ //<栈顶优先级 或 右括号 或 "#"
while(sym.top()!="#" && get_pri(str)<=get_pri(sym.top()) && sym.top()!="("){
bool res = 0; //临时结果
string res_str = ""; //临时结果的字符串形式(TRUE,FALSE)
top_str = sym.top(); //弹出栈顶运算符
sym.pop();
top_oper = oper.top(); //弹出第一个操作数
oper.pop();
if(top_str == "NOT"){ //单操作数 (只有NOT一个)
if(top_oper == "TRUE")
res = 0;
else if(top_oper == "FALSE")
res = 1;
else
res = 1 - reg_arr[top_oper[0] - 'A'];
}
else{ //双操作数
string sec_oper = oper.top(); //第二个操作数
oper.pop();
if(top_str == "AND"){ //AND
if(top_oper == "TRUE"){
if(sec_oper == "TRUE")
res = 1;
else if(sec_oper == "FALSE")
res = 0;
else
res = reg_arr[sec_oper[0] - 'A'];
}
else if(top_oper == "FALSE")
res = 0;
else{ //第一个操作数是寄存器
if(!reg_arr[top_oper[0] - 'A'])
res = 0;
else{
if(sec_oper == "TRUE")
res = 1;
else if(sec_oper == "FALSE")
res = 0;
else
res = reg_arr[sec_oper[0] - 'A'];
}
}
}
else{ //OR
if(top_oper == "TRUE")
res = 1;
else if(top_oper == "FALSE"){
if(sec_oper == "TRUE")
res = 1;
else if(sec_oper == "FALSE")
res = 0;
else
res = reg_arr[sec_oper[0] - 'A'];
}
else{ //第一个操作数是寄存器
if(reg_arr[top_oper[0] - 'A'])
res = 1;
else{ //第一个操作数为0
if(sec_oper == "TRUE")
res = 1;
else if(sec_oper == "FALSE")
res = 0;
else
res = reg_arr[sec_oper[0] - 'A'];
}
}
}
}
if(res == 1)
res_str = "TRUE"; //运算结果转换为字符串压栈
else
res_str = "FALSE";
oper.push(res_str);
if(str==")" && sym.top()=="("){ //遇到左括号退出循环
sym.pop();
break;
}
}
if(str != ")")
sym.push(str); //str入栈
}
}
str = "";
str_len = 0;
}
if(!oper.empty()){
string lst = oper.top();
if(lst == "TRUE")
return 1;
else if(lst == "FALSE")
return 0;
else
return reg_arr[lst[0] - 'A'];
}
else{
printf("oper stack is empty!");
return false;
}
}
int get_pri(string str)
{
int num = 6;
string prim[num] = {"#", ")", "OR", "AND", "NOT", "("};
for(int i=0; i<num; i++)
if(prim[i] == str)
return i;
return -1;
}
bool is_fork() //判断当前点是否分叉
{
for(int i=0; i<M; i++)
if(cur_poi.x == fork_point[i].x && cur_poi.y == fork_point[i].y)
return true;
return false;
}
void next_posi(int res, Point &poi) //计算下一个位置
{
int dir = cur_poi.dir; //到当前点的方向
if(res == 1){ //右拐
if(dir == 0){ //原左
poi.x = cur_poi.x;
poi.y = cur_poi.y+1;
poi.dir = 2;
}
else if(dir == 1){ //原右
poi.x = cur_poi.x;
poi.y = cur_poi.y-1;
poi.dir = 3;
}
else if(dir == 2){ //原上
poi.x = cur_poi.x+1;
poi.y = cur_poi.y;
poi.dir = 1;
}
else{ //原下
poi.x = cur_poi.x-1;
poi.y = cur_poi.y;
poi.dir = 0;
}
}
else if(res == 0){ //左拐
if(dir == 0){
poi.x = cur_poi.x;
poi.y = cur_poi.y-1;
poi.dir= 3;
}
else if(dir == 1){
poi.x = cur_poi.x;
poi.y = cur_poi.y+1;
poi.dir = 2;
}
else if(dir == 2){
poi.x = cur_poi.x-1;
poi.y = cur_poi.y;
poi.dir = 0;
}
else{
poi.x = cur_poi.x+1;
poi.y = cur_poi.y;
poi.dir = 1;
}
}
else{ //直走
if(dir == 0){
poi.x = cur_poi.x-1;
poi.y = cur_poi.y;
}
else if(dir == 1){
poi.x = cur_poi.x+1;
poi.y = cur_poi.y;
}
else if(dir == 2){
poi.x = cur_poi.x;
poi.y = cur_poi.y+1;
}
else{
poi.x = cur_poi.x;
poi.y = cur_poi.y-1;
}
poi.dir = dir;
}
}
bool is_out(Point poi) //检查(x,y)是否出界
{
if(poi.x<-N || poi.x>N || poi.y<-N || poi.y>N)
return true;
else
return false;
}
bool is_invert(int ®) //检查当前点是否转换点,若是,引用带回寄存器编号
{
for(int i=0; i<K; i++)
if(cur_poi.x == inv[i].a && cur_poi.y == inv[i].b){
reg = inv[i].c[0] - 'A';
return true;
}
return false;
}