week2 实验+作业

记录week2的实验三道题+作业两道题
迷宫老鼠 倒水问题 化学式 多关键字排序 扑克
作业:
一:迷宫老鼠:
Input:
  输入是一个5 × 5的二维数组,仅由0、1两数字组成,表示法阵地图。
Output
  输出若干行,表示从左上角到右下角的最短路径依次经过的坐标,格式如样例所示。数据保证有唯一解。
这道题在课堂上讲过很多次,但是一直没动手写,思路大概就是:初始化迷宫,设置固定的四种移动方式,利用bfs,移动的时候将经过的地方标记并且压栈;用栈储存经过的路线的坐标,当无路可走时就从栈里取元素恢复路线直到有路可走
思路还是比叫容易理解,但是写的时候很多细节容易出错。
代码如下:

//#include<bits/stdc++.h>
#include<iostream>
#include<stack> 
using namespace std;

struct position{
int x,y;	
};

int _map[7][7];
position offset[4];
void pre_map_offset()//初始化 地图 + 位移 
{
	for(int i=1;i<6;i++)
	for(int j=1;j<6;j++)
	cin>>_map[i][j];
	for(int i=0;i<7;i++){_map[i][0]=1;_map[0][i]=1;_map[6][i]=1;_map[i][6]=1;}
    offset[0].x=1;offset[0].y=0;//右 
    offset[3].x=-1;offset[3].y=0;//左
	offset[2].x=0;offset[2].y=1;//上
	offset[1].x=0;offset[1].y=-1;//下 
}
void check()
{
	for(int i=0;i<7;i++)
	{
	for(int j=0;j<7;j++)
	cout<<_map[i][j]<<" ";
    cout<<endl;
	}
	
	for(int i=0;i<4;i++)
	cout<<offset[i].x<<offset[i].y<<endl;	
}
void bfs(int sx,int sy,int dx,int dy)
{
	
  	stack<position>s;int nowi=0;
    position now;now.x=sx;now.y=sy;
    s.push(now);_map[now.x][now.y]=1; 
    //cout<<s.top().x<<endl;
    int count=10000;
    while(now.x!=dx||now.y!=dy)
    { //cout<<s.top().x<<" "<<s.top().y<<endl;
    //check(); 
	   	count--;if(count<0){cout<<" false from while";break;}	
        now.x=s.top().x;//从栈顶取元素 
		now.y=s.top().y;
    	for(nowi=0;nowi<4;nowi++)
    	{	
    		if(_map[now.x+offset[nowi].x][now.y+offset[nowi].y]==0)
			{ _map[now.x][now.y]=1;//若找到了可走区域 置为一 
			  now.x=now.x+offset[nowi].x;
			  now.y=now.y+offset[nowi].y; break;} 
		}
		if(nowi<=3){//将当前位置压栈 
			s.push(now);
		//	cout<<"hhhhhh"<<endl;
		}
		else{
			if(s.empty()){
			cout<<"error:stack empty! "<<endl;	return ;
			}
			//无位置 从栈顶取元素 
			_map[now.x][now.y]=1; 
			
			s.pop();
		} 
	}
	if(now.x==dx&&now.y==dy)
	;
	else cout<<"false!"<<endl;
	stack<position> rs;
	while(!s.empty())
	{
		position t;t.x=s.top().x-1; t.y=s.top().y-1;
		//cout<<t.x<<" "<<t.y<<endl;
		s.pop();
		rs.push(t);
	}
	while(!rs.empty())
	{
		cout<<"("<<rs.top().x<<", "<<rs.top().y<<")"<<endl;
		rs.pop();
			}	
}
int main()
{
	pre_map_offset();
//check();
	bfs(1,1,5,5);	
	
	return 0;
}

倒水问题:
也是一道见过很多次但是没深入思考的题目,感觉跟互质数的取余有关,课上讲时是找出固定的状态变化,然后用bfs一直找符合有C的水的状态
描述:
“fill A” 表示倒满A杯,"empty A"表示倒空A杯,“pour A B” 表示把A的水倒到B杯并且把B杯倒满或A倒空。
Input
输入包含多组数据。每组数据输入 A, B, C 数据范围 0 < A <= B 、C <= B <=1000 、A和B互质。
Output
你的程序的输出将由一系列的指令组成。这些输出行将导致任何一个罐子正好包含C单位的水。每组数据的最后一行输出应该是“success”。输出行从第1列开始,不应该有空行或任何尾随空格。

这道题我觉得对我这种新手来说还是挺难的;他难就难在我想不到这么做,联系不到bfs上,但是做完就觉得思路还是很合理的:
状态变化一共八种分别列举出来,初状态入队,重复将队首取出分别计算下一个状态并入队,直至找到合适的状态,在这里将状态用结构体表示,为了最后依序输出,这里为每个节点加上了它的前一个状态的坐标节点px 和 py,以flag表示是否遍历过,遍历过的不再入队。建立个足够大的结构体矩阵,用来存放杯子里水的不同状态。找到最终节点后就可以利用px py在图内遍历路径。

#include<iostream>
#include<queue>
using namespace std;
int a,b,c;
struct node{
	int x,y;
	int op;
	int px,py;
	int flag;
	
};
 int path[100000]={0};
node g[1005][1005];
void pre_g(){
	for(int i=0;i<1005;i++)
	{
		for(int j=0;j<1005;j++)
		{
			g[i][j].flag=-1;
			g[i][j].op=-1;
			g[i][j].x=0;g[i][j].y=0;
			g[i][j].px=-1;g[i][j].py=-1;
		}
	}
}

int lastx,lasty,lastop; 
int  bfs()
{
	queue<node>q;
	node now;now.op=-2 ;now.px=-1;now.py=-1;now.x=0;now.y=0;
	node next;
	q.push(now);now.flag=1;
	g[now.x][now.y].flag=-1;	g[now.x][now.y].op=-2;	g[now.x][now.y].px=-1;	g[now.x][now.y].py=-1;	g[now.x][now.y].x=0;	g[now.x][now.y].y=0;
	while(!q.empty())
	{
		//cout<<"inwhile"<<endl;
		now.flag=q.front().flag;
		now.x=q.front().x;
		now.y=q.front().y;
		now.op=q.front().op;
		now.px=q.front().px;
		now.py=q.front().py;
		
		for(int i=0;i<8;i++)// 
	    {	  
			if(i==0)
	  	    {
	  	    	next.x=a;
	  	    	next.y=now.y;
	  	    	next.op=0;
			}
			else if(i==1)
			{
			    next.x=now.x;
				next.y=b;
				next.op=1;	
			}
			else if(i==2)
			{
				next.x=0;
				next.y=now.y;
				next.op=2;
			}
			else if(i==3)
			{
				next.x=now.x;
				next.y=0;
				next.op=3;
			}
			else if(i==4&&(now.x+now.y)<=b) //将a倒入b  1、a空y=y+x;x=0;  
			{
				next.x=0;
				next.y=now.y+now.x;
				next.op=4;
			}
			else if(i==5&&(now.x+now.y)>b)// 2、a余下 b满 x=x+y-b;y=b;  
			{
				next.x=now.x+now.y-b;
				next.y=b;
				next.op=5;	
			}
			else if(i==6&&(now.x+now.y)<=a)//将b倒入a    1、b空  
			{
				next.x=now.x+now.y;
				next.y=0;
				next.op=6;
			}
			else if(i==7&&(now.x+now.y)>a)//2、b余下 a满
			{
				next.x=a;
				next.y=now.y-(a-now.x);
				next.op=7;
			}
			else{
				continue;
			}
			if(g[next.x][next.y].flag==-1&&next.x!=c&&next.y!=c){//若下个状态未经历过 并且不为目标状态 
			//cout<<i<<"    "<<now.x<<" "<<now.y<<"->"<<next.x<<" "<<next.y<<endl;
				next.px=now.x;next.py=now.y;next.flag=1;                     //将下个状态的前置状态置为当前状态  
				q.push(next);                                    //下个状态入队 
				
				g[next.x][next.y].x=next.x;g[next.x][next.y].y=next.y;//在状态图里将 下个状态 对应 节点更新 
				g[next.x][next.y].op=next.op;
				g[next.x][next.y].px=now.x;g[next.x][next.y].py=now.y;
			    g[next.x][next.y].flag=1;
			    
			}
			if(next.x==c||next.y==c)//若找到节点 
			{	//cout<<i<<"    "<<now.x<<" "<<now.y<<"->"<<next.x<<" "<<next.y<<endl;
			next.px=now.x;next.py=now.y;next.flag=1;
			g[next.x][next.y].x=next.x;g[next.x][next.y].y=next.y;
			g[next.x][next.y].op=next.op;
			g[next.x][next.y].px=now.x;g[next.x][next.y].py=now.y;
			g[next.x][next.y].flag=1;
			
			lastx=now.x;lasty=now.y;lastop=i;	int u=lastop;	
			int temp_x=lastx;int temp_y=lasty;int co=0;
       do
	   {
		if(u==0){
		path[co]=0;
		}
		if(u==1){
		path[co]=1;	
		}
		if(u==2){
		path[co]=2;	
		}
		if(u==3){
		path[co]=3;	
		}
		if(u==4||u==5){
		path[co]=4;	
		}
		if(u==6||u==7){
		path[co]=5;	
		}co++;
	   //cout<<"flag:"<<g[lastx][lasty].flag<<" op:"<<g[lastx][lasty].op<<" px:"<<g[lastx][lasty].px<<" py:"<<g[lastx][lasty].py<<" x:"<<g[lastx][lasty].x<<" y:"<<g[lastx][lasty].y<<endl;
		u=g[lastx][lasty].op;
		temp_x=lastx;temp_y=lasty;
		lastx=g[temp_x][temp_y].px;
		lasty=g[temp_x][temp_y].py;
	}while(g[temp_x][temp_y].x!=0||g[temp_x][temp_y].y!=0);
			for(int k=co-1;k>=0;k--){
			//	cout<<path[k]<<endl;
				if(path[k]==0){
					cout<<"fill A"<<endl;
				}
				if(path[k]==1){
					cout<<"fill B"<<endl;
				}
				if(path[k]==2){
					cout<<"empty A"<<endl;
				}
				if(path[k]==3){
					cout<<"empty B"<<endl;
				}
				if(path[k]==4){
					cout<<"pour A B"<<endl;
				}
				if(path[k]==5){
					cout<<"pour B A"<<endl;
				}
				
			}
			  return  1;	
			}
		
		}	
		q.pop();
		
    }

}

int main()
{
	while(scanf("%d%d%d",&a,&b,&c)!=EOF)
	{
		pre_g();
		bfs();
	    cout<<"success"<<endl;
	}
    return 0;
}

实验:
化学:
在这里插入图片描述
假设如上图,这个烷烃基有6个原子和5个化学键,6个原子分别标号1~6,然后用一对数字 a,b 表示原子a和原子b间有一个化学键。这样通过5行a,b可以描述一个烷烃基

你的任务是甄别烷烃基的类别。

原子没有编号方法,比如
1 2
2 3
3 4
4 5
5 6

1 3
2 3
2 4
4 5
5 6
是同一种
Input
输入第一行为数据的组数T(1≤T≤200000)。每组数据有5行,每行是两个整数a, b(1≤a,b≤6,a ≤b)
数据保证,输入的烷烃基是以上5种之一
Output
每组数据,输出一行,代表烷烃基的英文名

简而言之分辨这五种化学分子,这道题实验课之前没接触过,乍一看毫无思路,下午回过神来又看了看这个图突然发现了什么了不得的事情,第一个分子各个原子最大的连接其他原子数是2,第二三四个是3,第四个是4,但是第四个有两个为3,第三个与为3的原子相连的有两个为1的,第二个则有两个为2的,这样我们用图表示每个输入的分子,统计他们的度数即可。但是这道题还是差点令人爆炸,因为某些不明显的错误。

//#include<bits/stdc++.h>
#include<iostream>
using namespace std;
//1		0 0 0 1 0 0
//1		0 0 1 0 0 0
//2		0 1 0 1 0 0
//3		1 0 1 0 1 0
//2		0 0 0 1 0 1
//1		0 0 0 0 1 0
     int a[7][7];
void  out(){
	for(int i=0;i<7;i++)
	{for(int j=0;j<7;j++)
	{
		cout<<a[i][j]<<" ";
	 } cout<<endl;
	}
}
int main(){
   int T;cin>>T;
   for(int i=0;i<T;i++)
   {
     for(int ci=0;ci<7;ci++)for(int cj=0;cj<7;cj++)a[ci][cj]=0;
	 int x=0;int y=0;
	 int maxd=0;int maxcount=0;
	 int maxpx=0;
	 for(int j=0;j<5;j++)
	 {
	 	scanf("%d%d",&x,&y);
	 	if(x!=y&&a[x][y]!=1){
	 	a[x][y]=1;a[x][0]+=1;
	 	a[y][x]=1;a[y][0]+=1;
	 }
	 }  maxd=a[1][0];maxpx=1;
     for(int k=2;k<7;k++)
	 {
	 	if(maxd<a[k][0])
		 {maxpx=k;
		 maxd=a[k][0];
		 }
	 }
	// cout<<maxpx<<endl; 	 	
	    for(int kk=1;kk<7;kk++)
	    {
		if(a[kk][0]==maxd)
		maxcount++;
		}	
    //out();
    if(maxd==2)
    cout<<"n-hexane"<<endl;
    if(maxd==4)
    printf("2,2-dimethylbutane\n");
    if(maxd==3)
    {
    	if(maxcount==2)
    	cout<<"2,3-dimethylbutane"<<endl;
    	else if(maxcount==1)
    	{
    		int sec_count=0;int sec=0;
    		for(int jj=1;jj<7;jj++)
    		{
    			if(a[maxpx][jj]>0)
    			{
    				if(a[jj][0]>sec)
    				sec=a[jj][0];
				}
    			
			}
    	    for(int jj=1;jj<7;jj++)
    		{//cout<<a[maxpx][jj]<<" ";
    			if(a[maxpx][jj]>0)
    			{
    			  if(a[jj][0]==sec)
    			  sec_count++;	
				}	
			}
			if(sec_count==2)
			{
				cout<<"3-methylpentane"<<endl;
			}
			else if(sec_count==1)
			{
				cout<<"2-methylpentane"<<endl;
			}
			else cout<<"maxpx"<<endl;
			//cout<<sec<<" "<<sec_count<<endl;
		}
		else cout<<"error in maxd=3"<<endl;
	}
	
}
	
	return 0;
}

成绩
描述:

例如某次考试一共八道题(A,B,C,D,E,F,G,H),每个人做的题都在对应的题号下有个数量标记,负数表示该学生在该题上有过的错误提交次数但到现在还没有AC,正数表示AC所耗的时间,如果正数a跟上了一对括号,里面有个正数b,则表示该学生AC了这道题,耗去了时间a,同时曾经错误提交了b次。例子可见下方的样例输入与输出部分。
Input
输入数据包含多行,第一行是共有的题数n(1≤n≤12)以及单位罚时m(10≤m≤20),之后的每行数据描述一个学生的信息,首先是学生的用户名(不多于10个字符的字串)其次是所有n道题的得分现状,其描述采用问题描述中的数量标记的格式,见上面的表格。
Output
根据这些学生的得分现状,输出一个实时排名。实时排名显然先按AC题数的多少排,多的在前,再按时间分的多少排,少的在前,如果凑巧前两者都相等,则按名字的字典序排,小的在前。每个学生占一行,输出名字(10个字符宽),做出的题数(2个字符宽,右对齐)和时间分(4个字符宽,右对齐)。名字、题数和时间分相互之间有一个空格。数据保证可按要求的输出格式进行输出。
这道题思路相当明显了,跟第一周的多关键字排序类似,但是我做起来还是感觉很麻烦,涉及到一大堆输入、string、排序之类的操作。刚开始做做的很慢,而且因为不熟悉string和char操作,还有各种bug。后来看了一个大神代码才发现竟然可以这么做,几十行代码就完成了,这里就不贴我的垃圾代码了
总之就是:
用:scanf(" %d(%d)",&sco,&psco);来按照格式读取输入数据(我用的字符串……淦!
然后利用自己写的cmp比较函数进行sort排序(我刚开始用的自己写的……

bool cmp(node a,node b)
{
	if(a.ts==b.ts)
	{
		if(a.fs==b.fs)
			return a.n<b.n;
		return a.fs<b.fs;
	}	
	return a.ts>b.ts;
}

	sort(s,s+j,cmp);
	for(int i=0;i<j;i++)
	{
	printf("%-10s %2d %4d\n",s[i].n,s[i].ts,s[i].fs);
    }

扑克排序
太长了……插个原题超链接吧:here
总的来说,就是分东南西北,指定一个人发牌,发52张牌,按照给定的花色和大小排序输出。
因为牌有TJQKA这种大小的类型,也有CDSH这种花色代号。可以用map之类设定大小,我这里之即采用的数组,用c['K']=13;c['A']=14;这种方式获得大小。扑克用结构体表示花色和大小;为了保存每个人的牌,我设定了结构体存储人名和扑克结构体。然后就可以利用cmp比较函数和sort直接排序。
最后也是有一些错误没发现导致折腾了很长时间(我以为每个样例都有一个代表结束的#……

#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
struct node{
	char n;
	char x;
};
struct player{
	char *name;
	node poker[14];	
	int _count;
};
int  c[130]={0};
void precmp()
{
   c['C']=1;c['D']=2;c['S']=3;c['H']=4;//花色
   c['2']=2;c['3']=3;c['4']=4;c['5']=5;c['6']=6;c['7']=7;c['8']=8;c['9']=9;c['T']=10;c['J']=11;c['Q']=12;c['K']=13;c['A']=14; 
}
bool cmp(node a,node b){
	if(c[a.n]==c[b.n])
	{
         return c[a.x]<c[b.x];
	}
	return c[a.n]<c[b.n];
}
string line1,line2;
player P[5];


int main(){

	precmp();
	P[0].name="South";P[1].name="West";P[2].name="North";P[3].name="East";
	char fp='0';int flag=0;
while(cin>>fp)
{
	if(fp=='#')break;
	for(int i=0;i<4;i++)P[i]._count=0;
	
	for(int i=0;i<4;i++)if(fp==P[i].name[0]){flag=i+1;flag=flag%4;}//cout<<flag<<"fdvverver"<<endl;}
	cin>>line1>>line2;
	//char ws='0';cin>>ws;
	int sum=0;
	for(int i=0;i<26;i++)
	{
		if(P[flag]._count<14&&flag<4){
	  	P[flag].poker[P[flag]._count].n=line1[sum];sum++;
	  	P[flag].poker[P[flag]._count].x=line1[sum];sum++;
	  	P[flag]._count++;flag=flag+1;flag=flag%4;
        }
	 } 
	 sum=0;
	for(int i=0;i<26;i++)
	{
	  if(P[flag]._count<14&&flag<4){
	    P[flag].poker[P[flag]._count].n=line2[sum];sum++;
	  	P[flag].poker[P[flag]._count].x=line2[sum];sum++;
	  	P[flag]._count++;flag=flag+1;flag=flag%4;
	  }
	 }
	for(int j=0;j<4;j++)
	sort(P[j].poker,P[j].poker+13,cmp);
    for(int i=0;i<4;i++)
	{
		cout<<P[i].name<<" player:"<<endl;
		cout<<"+---+---+---+---+---+---+---+---+---+---+---+---+---+"<<endl;
		for(int j=0;j<13;j++)
		cout<<"|"<<P[i].poker[j].x<<" "<<P[i].poker[j].x;
		cout<<"|"<<endl;
		for(int j=0;j<13;j++)
		cout<<"|"<<" "<<P[i].poker[j].n<<" ";
		cout<<"|"<<endl;
		for(int j=0;j<13;j++)
		cout<<"|"<<P[i].poker[j].x<<" "<<P[i].poker[j].x;
		cout<<"|"<<endl;	
		cout<<"+---+---+---+---+---+---+---+---+---+---+---+---+---+"<<endl;
		}	
		cout<<endl;
 } 
	return 0;
}

经过这周的实验,虽然有在家效率太低了的原因,但是确实主要还是因为自己的菜,这几道题折腾了好多天拖拖拉拉才写完,码力还有待加强

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值