我的作业之旅之程序设计思维与实践 Week2 作业和实验题(共五道)

(预警:本人英语不好还是个起名废,所以请不要纠结于奇奇怪怪的变量名)
Week2 作业题 A-Mase
题干如图思路:将迷宫的每一个点设为一个节点类point,包含该点的坐标,然后再建立一个存储当前节点的前一个节点的坐标的结构体nod,用nod定义一个二维数组former专门存放每个节点的前一个节点的坐标,都初始化为(-1,-1),这么初始化一方面可以用作标记判断,另一方面可以从终点向起点找路径时及时终止。再建立一个int型的二维数组存放每个坐标处的数值。此题是一个热血少年从迷宫起点出发探险中途避开障碍物并最终以最快的速度找到出口迎取白富美的故事,所以显然是一个宽度优先搜索,妹子算什么,哥这一片的红buff蓝buff全都要!扯远了,宽搜先找到的路径是最近的,所以我建立了一个队列,直接调用STL里的工具,一个节点是队列的一个元素,把当前节点附近的非零非重复节点存到里面,存入的节点根据坐标更新former数组坐标,然后删除当前节点,继续取首元素找临近元素存入队列,直到找到终点元素。找到终点节点后,再利用former数组层层前推找到起点达成最短路径,为了正序输出,用栈存放路径输出。至于我为什么要说的这么啰嗦,因为我不详细说我也理不清自己的思路啊喂ヽ(●-`Д´-)ノ

#include<iostream>
#include<queue>
#include<cmath>
#include<stack>
using namespace std;
class point
{
	public:
		point()
		{
			x=y=0;
		}
		point(int _x, int _y)
		{
			x = _x;
			y = _y;
		}
		int cx()
		{
			return x;
		}
		int cy()
		{
			return y;
		}
		point origin()
		{
			return point(0,0);
		}
	/*	double distance(point& another)
		{
			return sqrt((x-another.x)*(x-another.x)+(y-another.y)*(y-another.y));
		}*/
	private:
		int x,y;
}; //定义每个节点坐标 
struct nod
{
	int m;
	int n;
}; //当前节点的前一个节点坐标 
nod former[5][5];//每个格子的前一个路径 (包括每一个点)
void chushi()
{
	for(int i=0;i<5;i++)
	{
		for(int j=0;j<5;j++)
		{
			former[i][j].m=-1;
			former[i][j].n=-1;
		}
 	}//初始化路径,1.宽搜时判断该点是否被标记(是否有前一个节点)2.最后输出路径时用这个来寻找 
} 
int a[5][5];//迷宫每个格子内的数(节点状态) 
int sx=0;
int sy=0;//当前节点的坐标索引 
queue<point> Q;//队列,用于记录层层拓展的中间节点 
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
void bfs()
{
	Q.push(point(sx,sy));//将原点压入队列 
	former[sx][sy].m=0;//标记原点的前一个点为(0,-1),这样该点既不是没标记过的(-1,-1),也意味着路径的端点  
	while(!Q.empty())
	{
		point now =Q.front();//取点 
		Q.pop();//删除头节点 
		for(int i=0;i<4;++i)//特判合法性,加入队列 
		{
			int x1=now.cx()+dx[i];
			int y1=now.cy()+dy[i];
			if(x1>=0&&x1<=4&&y1>=0&&y1<=4&&a[x1][y1]==0&&former[x1][y1].m==-1&&former[x1][y1].n==-1)
			{
				former[x1][y1].m=now.cx();
				former[x1][y1].n=now.cy();//符合条件的新节点压入队列,新节点用当前节点的坐标标记。 
				Q.push(point(x1,y1));
			}
		}
	}
} 
void out()//输出函数 
{
	stack<point> s;//用栈存放路径的点 
	s.push(point(4,4));//先把最后一个点放进去 
	int i=4;
	int j=4;//路径索引 
	int r,t;//当前节点的前一个节点的索引 
	while(i>=0&&j>=0)//不停找前一个点,直到到原点为止(因为我将原点的前一个点的坐标设为了(-1,0)) 
	{
		if(i==0&&j==0)
		break;
		r=former[i][j].m;
		t=former[i][j].n;
		s.push(point(r,t));
		i=r;
		j=t;
	}//将前一个点压入栈,同时索引同步向前
	while(!s.empty()) 
	{
		point now1=s.top();
		cout<<"("<<now1.cx()<<", "<<now1.cy()<<")"<<endl;
		s.pop();
	}
	
}
int main()
{
	for(int i=0;i<5;i++)
	{
		for(int j=0;j<5;j++)
		{
			cin>>a[i][j];
		}
	 } 
	 chushi();
	 bfs();
	 out();
	 return 0;
}

Week2 作业题 B-Pour Water
题干如图思路:本来这个题目,我想将每个状态作为一个节点,每个节点包括a,b杯水的含量,6种操作用六个函数分别返回一种状态,建立一个队列,从初始状态开始,每个状态经过可实行的操作后得到一个新的状态,若新的状态未被标记,则存入队列,为了得到当前状态的的前一状态,建立一个数组,对应当前状态的前一状态的索引,还有一个数组对应当前状态的是由哪种操作得来的,最后由末状态向前一步步寻找初始状态,并输出操作。但是,由于我匮乏的码力和调试能力属实渣,代码运行不出来。
于是我最终选择了用map的方法,主要思路就是还是每个状态包括a,b杯的含水量用map连接一个个母状态和子状态,然后用队列存放所有可能的状态,直到遇到目标状态,然后输出的时候,根据子母状态大小来判断他们之前进行了哪一项操作,例如如果子母状态的a杯水没有变过,那么一定是灌满b或者倒空b,就看b里是不是B的水量。另外,在输出的时候巧妙运用一个递归,不断从孩子找妈妈,找到宗祖母,开始输出两个状态之间的操作,就可以正序输出了(此处借鉴了大佬的思路)。

#include<iostream>
#include<map>
#include<queue>
using namespace std;
int A,B,C;
struct node
{
	int x;
	int y;
	bool operator < (const node &s)const
	{
		return x!=s.x ? x<s.x : y<s.y;
	}
};//定义状态结构体 
map<node,node>road;//定义路径map,第一个参数是子状态,后一个状态是母状态 
queue<node> Q;
void add(node &mum,node &child)
{
	if(child.x==0&&child.y==0)      return;//初始状态,排除不能加入队列 
	if(road.find(child)==road.end())//子状态之前没出现过 ,加入队列 
	{
		Q.push(child);
		road[child]=mum;//记录路径母子关系 
	}
}
void out1(node &child)//输出路径变化,利用map求母子关系,然后比较母子大小判断是什么变化
{
	node &mum=road[child];
	if(mum.x==child.x)//a杯子没变 
	{
		if(child.y==B) 
		cout<<"fill B"<<endl;
		else 
		cout<<"empty B"<<endl;
	}
	else if(mum.y==child.y)//b杯子没变 
	{
		if(child.x==A) 
		cout<<"fill A"<<endl;
		else 
		cout<<"empty A"<<endl;
	}
	else//都变了 
	{
		if(child.x<mum.x) 
		cout<<"pour A B"<<endl;
		else  
		cout<<"pour B A"<<endl;
	}
 } 
 void out(node &child)
 {
 	if(road.find(child)==road.end())//从孩子出发找妈妈,然后递归输出路径 
	{
		return;
	}
	out(road[child]);
	out1(child);
	return;
 }
 void bfs()
 {
 	node tmum,thechild; //祖母和当前子女 
	tmum.x=0;tmum.y=0;
	Q.push(tmum);
	while(!Q.empty())
	{
		node nowmum=Q.front();//当前母亲 
		Q.pop();
		if(nowmum.x==C||nowmum.y==C)
		{
			out(nowmum);
			return;
		}
		if(nowmum.x>0)
		{
			thechild.x=0;
			thechild.y=nowmum.y;
			add(nowmum,thechild);
		}
		//倒空b的水
		if(nowmum.y>0)
		{
			thechild.y=0;
			thechild.x=nowmum.x;
			add(nowmum,thechild);
		}
		//a没有满,加满a
		if(nowmum.x<A)
		{
			thechild.x=A;
			thechild.y=nowmum.y;
			add(nowmum,thechild);		
			//将b的水倒入a
			if(nowmum.y!=0)
			{
				if(nowmum.y+nowmum.x<=A)
				{
					thechild.x=nowmum.x+nowmum.y;
					thechild.y=0;
					add(nowmum,thechild);
				}
				else
				{
					thechild.x=A;
					thechild.y=nowmum.y+nowmum.x-A;
					add(nowmum,thechild);
				}
			}
		}
		//b没有满,加满b
		if(nowmum.y<B)
		{
			thechild.y=B;
			thechild.x=nowmum.x;
			add(nowmum,thechild);

			//将a的水倒入b
			if(nowmum.x!=0)
			{
				if(nowmum.y+nowmum.x>B)
				{
					thechild.y=B;
					thechild.x=nowmum.x+nowmum.y-B;
					add(nowmum,thechild);

				}
				else
				{
					thechild.y=nowmum.x+nowmum.y;
					thechild.x=0;
					add(nowmum,thechild);
				}
			}
		}
	}
	//cout<<"success"<<endl;
 }
 int main()
 {
 	while(cin>>A>>B>>C)
 	{
 		while(!Q.empty())
 		Q.pop();
 		road.clear();
 		bfs();
 		cout<<"success"<<endl;
	 }
	 return 0;
 }

Week2 实验题 A
题目用图
题干如图思路:我一开始的思路是找到每一个结构里的所有最短路径,我发现正己烷只有一条最短路径,2-戊烷有3条,分别为233,3-戊烷有三条,分别为334,2,3-2丁烷有四条,分别为2233,跟2,2-2丁烷一样,但是2,2-2丁烷一个原子最多有四个化学键,而2,3-2丁烷最多有仨,于是这样可以把五种结构都区分开。但是光看我诉说就可以想见这个办法写出程序来有多复杂,所以在尝试无果之后果断放弃,选择了另一种相对简单的方法。利用不同化学键原子的个数。我用了一个数组结构体来记录每种结构体的不同键个数的原子的个数,(索引对应键数)按照上述顺序分别为
{0,2,4,0,0}
{0,3,2,1,0}
{0,3,2,1,0}
{0,4,1,0,1}
{0,4,0,2,0}
然后我发现通过比较每个数组的第三项可以区分出正己烷、2,3-2丁烷、2,2-2丁烷,而剩下的两种结构,可以比较与化学键最多的原子相连的原子的化学键总数来比较。

#include<iostream>
using namespace std;
struct yuanzi
	{
		int num;//初始化与该原子相邻的化学键个数 
		int node[5];//分别对应每个原子相邻的原子 
	};

int main()
{
	yuanzi tree[7];//用后六个数组结构体,分别对应六个原子 
	int n;//输入几组数 
	int a,b;//输入两个原子编号 
	int s,t;// 作为该原子化学键个数的代指量 
	int sum;//二次判断,通过最多键原子相邻原子的键个数之和判断2 和3那两种情况 
	cin>>n;	
	for(int i=0;i<n;i++)//循环几组数 
	{
		for(int e=0;e<7;e++)
		{
			tree[e].num=0;
			for(int q=0;q<5;q++)
			{
				tree[e].node[q]=0;
			}
		}
		sum=0;
		int jian[5]={0,0,0,0,0};//记录该结构对应连接化学键某个个数的原子的个数
		for(int j=0;j<5;j++)// 循环输入5个化学键 
		{
			cin>>a>>b;	
			s=tree[a].num;
			t=tree[b].num;
			tree[a].node[s]=b;
			tree[b].node[t]=a;
			tree[a].num++;
			tree[b].num++;
		}
		for(int j=1;j<7;j++)
		{
			s=tree[j].num;//某原子的化学键个数 
			jian[s]++; //对应个数化学键的原子数增加 
		}
		if(jian[2]==4) //此时{0,2,4,0,0} 
		cout<<"n-hexane"<<endl;
		else if(jian[2]==1)//此时{0,4,1,0,1} 
		cout<<"2,2-dimethylbutane"<<endl;
		else if(jian[2]==0)//此时 {0,4,0,2,0}
		cout<<"2,3-dimethylbutane"<<endl;
		else//{0,3,2,1,0} 
		{
			int y=1;
			while(tree[y].num!=3)
			y++;//找到连接三个键的原子 
			for(int j=0;j<3;j++)//找到与该原子相连的原子 ,并将各原子化学键个数相加 
			{
				int w=tree[y].node[j];//记录原子序号
				sum=sum+tree[w].num; 
			}
			if(sum==4)
			cout<<"2-methylpentane"<<endl;
			else
			cout<<"3-methylpentane"<<endl;
		}
	}
	return 0; 
}

Week2 实验题 B
题干如图思路:首先定义学生结构体,包括名字、答题数、总用时,并且重载比较符,便于最后将学生排序输出。然后是处理输入,采用一输入一处理,用char数组暂存每个输入数据,然后判断第一个字符,若为正,该学生答题数增加,将‘(’之前的数据加入该学生总用时,‘(’之后的数据*m加入总用时;若为负,参考括号内做法答题数不变;若为0;答题数不变。对字符串的处理方法利用了数字的ACS码。

#include<iostream>
#include<string>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<iomanip>
using namespace std;
struct stu
	{
		string name;
	//	char score[8];	
		int num;//答出题数
		int sum;//总耗时 
		bool operator <(const stu &a)const
		{
			if(num!=a.num)
			return num>a.num;
			if(sum!=a.sum)
			return sum<a.sum;
			int l1=name.length();
			int l2=a.name.length();
			for(int i=0;i<min(l1,l2);i++)
			{
				if(name[i]==a.name[i]) continue;
				if(name[i]<a.name[i]) return true;
				if(name[i]>a.name[i]) return false;
			}
			if(l1<l2) return true;
			return false;
		 } //重载比较运算符,便于将学生排序输出 
	};//定义学生结构体 
	stu *kaosh=new stu;//定义学生结构体数组
	int n,m;
	
int main()
{
	cin>>n>>m;//题数和每次罚时 
	int i=0;//学生的索引 
	char s[1000]; //每个学生每道题的记录 
	while(cin>>s)//输入名字 
	{
		kaosh[i].name=s;
		kaosh[i].num=0;
		kaosh[i].sum=0;
		for(int j=0;j<n;j++)//输入记录 
		{
			cin>>s;
			int e=0;//该字符的索引 
			int l=strlen(s);//该字符串长度
			if(s[e]!='-'&&s[e]!='0')//当记录的是正数时 
			{
				int um=0;
				kaosh[i].num++;//答对题数+1 
				//e++;
				//string ss;//存放算数的字符串 
				//int ee=0;//算数字符串的索引 
				while(e<l&&s[e]!='(')//遇到括号之前 (计算括号之前的分数) 
				{
					//ss[ee]=s[e];
					//ee++; 
					um=um*10+s[e]-'0';
					e++;
				}
				//stringstream ssr;
				//double a;
				//ssr<<ss;
				//ssr>>a;
				kaosh[i].sum=kaosh[i].sum+um;
				//ee=0; 
				um=0;
				while(e<l&&s[e]!=')')//遇到括号之后(计算括号里的分数)/若没有括号后面为空,不进行循环 
				{
					//ss[ee]=s[e];
					//ee++;
					um=um*10+s[e]-'0';
					e++;
				} 
				kaosh[i].sum=kaosh[i].sum+um*m;
			}
			else//当是负数或者为0时 
			{
				if(s[e]=='-')
				{
					e++;
					//string ss;//存放算数的字符串 
					//int ee=0;//算数字符串的索引 
					int um;
					while(e<l)
					{
						//ss[ee]=s[e];
						um=um*10+s[e]-'0';
					}
				//	stringstream ssr;
				//	double a;
				//	ssr<<ss;
				//	ssr>>a;
					kaosh[i].sum=kaosh[i].sum+um*m;
				}
			}
		}
		i++;
	}
	int z=i;//记录学生个数
	sort(kaosh+1,kaosh+z);
	for(int dd=0;dd<z;dd++)
	{
		cout<<left<<setw(10)<<kaosh[dd].name<<" ";
		cout<<right<<setw(2)<<kaosh[dd].num<<" "<<setw(4)<<kaosh[dd].sum<<endl;
	}
	return 0;
} 

week2实验C
题干如图思路:先定义扑克牌结构体,包括花色和牌数,然后我将花色和牌数分别转化为数字,这样便于重载比较符,(一开始我想用宏定义,结果发现方位里的S与花色重叠)然后用链表把每一个玩家的牌连接起来,在插入新节点的时候,用指针去比较寻找合适的位置插入。然后再建一个链表数组,分别代表每个方位的玩家。为了数据能按照顺时针顺序存储到相应的玩家的链表里,再建立一个路劲数组,对应索引存储的是下一个方位的索引,最后按照0-3的顺序输出链表

#include<iostream>
#include<string.h>
/*#define C 15
#define D 16
#define S 17
#define H 18//花色 
#define T 10
#define J 11
#define Q 12
#define K 13
#define A 14*/
using namespace std;
int suitturn(char suit)
{
	if(suit=='C') return 15;
	if(suit=='D') return 16;
	if(suit=='S') return 17;
	if(suit=='H') return 18;
}
int numturn(char num)
{
	if(num=='T') return 10;
	if(num=='J') return 11;
	if(num=='Q') return 12;
	if(num=='K') return 13;
	if(num=='A') return 14;
	if(num>'1'||num<='9') return num-'0';
}
struct node{
	char suit;//花色,C(梅花)D(方片)S(黑桃)H(红桃) 
	char num;//扑克牌数值
	int x,y;
	void cx()
	{
		x=suitturn(suit);
	}
	void cy()
	{
		
		y=numturn(num);
	}
	
	bool operator < (const node&s)
	{		
		return x!=s.x ? x<s.x : y<s.y;
	}
	node *next;
}man[4];// 一张牌为一个节点,每个节点连接下一个节点
int former[4]={1,2,3,0};
int main()
{
	char n;
	cin>>n;
	char a[100];
	char b[100];//分别存储两行牌 
	cin>>a>>b;//输入两行牌 
	int xu;//作为 man数组的索引 
	while(n!='#')
	{
		if(n=='S')
		xu=1;
		else if(n=='W')
		xu=2;
		else if(n=='N')
		xu=3; 
		else
		xu=0;
		int s1=0;//字符串的索引 
		for(int i=0;i<4;i++)
		{
			char c[100];
			node *firstnode;
			firstnode=&man[xu];
			node *newnode;
		//	node *p=firstnode;
			node *pp;
			for(int j=0;j<13;j++)
			{
				strncpy(c, a, 1000);
				if(i==2)
				{
					strncpy(c, b, 1000);
				}
				newnode->suit=c[s1];
				s1++;
				newnode->num=c[s1];
				s1++;
				if(s1==26)
				s1=0;
				node *p=firstnode;
				pp=p;
				while(p->next!=NULL)
				{
					if(p<newnode)
					{
						pp=p;
						p=p->next;
					}
					
					else 
					{
						if(p==firstnode)
						{
							man[xu]=*newnode;
							man[xu].next=p;
							firstnode=&man[xu];
						}
						else
						{
							pp->next=newnode;
							newnode->next=p;
						}
						
					}
				}
				
			}
			xu=former[xu];
		}
		for(int i=0;i<4;i++)
		{
			if(i==0)
			cout<<"South player:"<<endl;
			else if(i==1)
			cout<<"West player:"<<endl;
			else if(i==2)
			cout<<"North player:"<<endl;
			else
			cout<<"East player:"<<endl;
			cout<<endl;
			cout<<"+---+---+---+---+---+---+---+---+---+---+---+---+---+"<<endl;
			cout<<endl;
			node *p=&man[i];
			while(p!=NULL)
			{
				cout<<"|"<<p->num<<" "<<p->num;
				p=p->next;
			}
			cout<<"|"<<endl;
			cout<<endl;
			p=&man[i];
			while(p!=NULL)
			{
				cout<<"|"<<" "<<p->suit<<" ";
				p=p->next;
			}
			cout<<"|"<<endl;
			cout<<endl;
			p=&man[i];
			while(p!=NULL)
			{
				cout<<"|"<<p->num<<" "<<p->num;
				p=p->next;
			}
			cout<<"|"<<endl;
			cout<<endl;			
		}		
		cin>>n;
	}
 } 

emmm,由于我的码力实在是匮乏,最后两篇代码至今没有运行成功,下一次我再补发一篇关于修改调试经过的帖子吧,跟下次作业一起。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值