程序设计思维与实践 Week2 作业&实验

  1. A - Maze

东东有一张地图,想通过地图找到妹纸。地图显示,0表示可以走,1表示不可以走,左上角是入口,右下角是妹纸,这两个位置保证为0。既然已经知道了地图,那么东东找到妹纸就不难了,请你编一个程序,写出东东找到妹纸的最短路线。

Input   输入是一个5 × 5的二维数组,仅由0、1两数字组成,表示法阵地图。

Output   输出若干行,表示从左上角到右下角的最短路径依次经过的座标,格式如样例所示。数据保证有唯一解。

思路:这是一道搜索题,可以使用BFS,过程中记录一下前驱节点,最后倒叙BFS输出路径。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define LL long long
using namespace std;
struct da {int x,y,t;};
int dx[5]={0,-1,1,0,0};
int dy[5]={0,0,0,1,-1};
bool v[20][20];
int m[20][20],s[20][20],a[30],b[30];
void BFS()
{
	da xx;xx.x=1,xx.y=1,xx.t=1;s[1][1]=1;v[1][1]=1;a[1]=b[1]=1;
	queue<da>q;q.push(xx);
	while(!q.empty())
	{
		da u=q.front();q.pop();
		int x=u.x,y=u.y,t=u.t;
		for(int i=1;i<=4;i++)
		{
			int xx=x+dx[i],yy=y+dy[i];
			if(xx>=1&&xx<=5&&yy>=1&&yy<=5&&!v[xx][yy]&&!m[xx][yy])
			{
				v[xx][yy]=true;
				s[xx][yy]=t+1;
				da r;r.x=xx,r.y=yy,r.t=t+1;
				q.push(r);
			}
		}
	}
	return ;
}
int main()
{
	for(int i=1;i<=5;i++)
	  for(int j=1;j<=5;j++)
	    scanf("%d",&m[i][j]);
	BFS();
	int i=1;int n=s[5][5],x=5,y=5;a[n]=b[n]=5;
	while(n--)
	{
		for(int i=1;i<=4;i++)
		{
			int xx=x+dx[i],yy=y+dy[i];
			if(xx>=1&&xx<=5&&yy>=1&&yy<=5&&s[xx][yy]==s[x][y]-1)
			{
				x=xx;y=yy;break;
			}
		}
		a[n]=x,b[n]=y;
	}
	for(int i=1;i<=s[5][5];i++)
	{
		printf("(%d, %d)\n",a[i]-1,b[i]-1);
	}
	  
	return 0;
}

总结:搜索用一遍BFS,输出用一遍BFS。

  1. B - Pour Water

倒水问题 “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列开始,不应该有空行或任何尾随空格。

思路:数据规模比较小,状态数不会超过C^2。有6种转移方法,记录一个状态数组b[i,j],表示(i,j)这个状态的出现与否,这题并不需要用最小代价,所以不必要记录状态的步数,只需要记录一下到达此状态的操作类型即可。最后递归输出方案。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define LL long long
using namespace std;
struct da {int x,y,t;}pre[1001][1001];
int A,B,C;
bool b[1001][1001];
void solve(int x,int y)
{
	da u=pre[x][y];
	if(!u.x&&!u.y) ;
	else solve(u.x,u.y);
	int z=pre[x][y].t;
	if(z==1) printf("fill A\n");
	if(z==2) printf("empty A\n");
	if(z==3) printf("fill B\n");
	if(z==4) printf("empty B\n");
	if(z==5) printf("pour A B\n");
	if(z==6) printf("pour B A\n");
	return ;
}
void BFS()
{
	memset(b,0,sizeof b);
	da xx;xx.x=0,xx.y=0,xx.t=1;
	queue<da>q;q.push(xx);
	while(!q.empty())
	{
		da u=q.front();q.pop();da v; 
		int x=u.x,y=u.y;
		if(x==C||y==C) {solve(x,y);return ;}
		if(!b[A][y]) {u.t=1;pre[A][y]=u;v.x=A,v.y=y;b[A][y]=true,q.push(v);}
		if(!b[0][y]) {u.t=2;pre[0][y]=u;v.x=0,v.y=y;b[0][y]=true,q.push(v);}
		if(!b[x][B]) {u.t=3;pre[x][B]=u;v.x=x,v.y=B;b[x][B]=true,q.push(v);}
		if(!b[x][0]) {u.t=4;pre[x][0]=u;v.x=x,v.y=0;b[x][0]=true,q.push(v);}
		int z=min(x,B-y);
		if(!b[x-z][y+z]) {u.t=5;pre[x-z][y+z]=u;v.x=x-z,v.y=y+z;b[x-z][y+z]=true,q.push(v);}
		z=min(A-x,y);
		if(!b[x+z][y-z]) {u.t=6;pre[x+z][y-z]=u;v.x=x+z,v.y=y-z;b[x+z][y-z]=true,q.push(v);}
		
	} 
	return ;
}

int main()
{
	while(scanf("%d%d%d",&A,&B,&C)!=EOF)
	{
		b[0][0]=true;
		BFS();int i=1;
		printf("success\n");
	}  
	return 0;
}

总结:如果输出步骤正向不好写,可考虑递归。

  1. A - 化学 (编译器选 GNU G++) Gym - 270437A

题目描述: 化学很神奇,以下是烷烃基。

ALT

假设如上图,这个烷烃基有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: 每组数据,输出一行,代表烷烃基的英文名

思路:这是一道模拟题目的是区分五种物质,可以将原子抽象成点,将化学键抽象成边建图。用以下几种策略区分:
1.每个点的度数 。 这样就可以区分出三种物质,还有两种无法区分。
2.对于那两种物质,看度数为3的点的位置,例如可以看它与端点的距离。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LL long long
using namespace std;
int a[7],b[7];
bool s[10][10];
int check()
{
	int tot=0;
	for(int i=1;i<=6;i++){
		if(a[i]==2) tot++;
	}
	if(tot==4) return 1;
	if(tot==2)
	{
		for(int i=1;i<=6;i++)
		  {
		  	if(a[i]==1)
		  	{
		  		for(int j=1;j<=6;j++)
		  		{
		  			if(j==i||a[j]!=1) continue;
		  			for(int k=1;k<=6;k++)
		  			{
		  				if(s[i][k]&&s[j][k]) return 2;
		  			}
		  		}
		  	}
		  }
		return 3;
	}
	tot=0;
	for(int i=1;i<=6;i++){
		if(a[i]==4) tot++;
	}
	if(tot) return 5;
	return 4;
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int x,y;
		for(int i=1;i<=6;i++) a[i]=b[i]=0;
		for(int i=1;i<=6;i++)
		  for(int j=1;j<=6;j++)
		    s[i][j]=0;
		for(int i=1;i<=5;i++)
		{
			scanf("%d%d",&x,&y);
			a[x]++;a[y]++;s[x][y]=s[y][x]=1;
		}
		x=check();
		if(x==1) printf("n-hexane\n");
		if(x==2) printf("2-methylpentane\n");			
		if(x==3) printf("3-methylpentane\n");			
		if(x==4) printf("2,3-dimethylbutane\n");			
		if(x==5) printf("2,2-dimethylbutane\n");			
		
	}
	return 0;
} 

总结:要仔细观察

  • B - 爆零(×)大力出奇迹(√) HDU - 2093

程序设计思维作业和实验使用的实时评测系统,具有及时获得成绩排名的特点,那它的功能是怎么实现的呢?
我们千辛万苦怼完了不忍直视的程序并提交以后,评测系统要么返回AC,要么是返回各种其他的错误,不论是怎样的错法,它总会给你记上一笔,表明你曾经在这儿被坑过,而当你历经千辛终将它AC之后,它便会和你算笔总账,表明这题共错误提交了几次。
在岁月的长河中,你通过的题数虽然越来越多,但通过每题时你所共花去的时间(从最开始算起,直至通过题目时的这段时间)都会被记录下来,作为你曾经奋斗的痕迹。特别的,对于你通过的题目,你曾经的关于这题的每次错误提交都会被算上一定的单位时间罚时,这样一来,你在做出的题数上,可能领先别人很多,但是在做出同样题数的人中,你可能会因为罚时过高而处于排名上的劣势。
例如某次考试一共八道题(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个字符宽,右对齐)。名字、题数和时间分相互之间有一个空格。数据保证可按要求的输出格式进行输出。

思路:字符串处理模拟题,提取出每个人的成绩,罚时和名字,再用sort排个序即可

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<iomanip>
#include<cmath>
#define LL long long
using namespace std;
int n,m,tot;
struct da{int x,t;string name;}a[1001];
char s[1001];
int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
	return x*f;  
}
int cmp(const da &x,const da &y)
{
	if(x.x!=y.x) return x.x>y.x;
	if(x.t!=y.t) return x.t<y.t;
	int l1=x.name.length(),l2=y.name.length();
	for(int i=0;i<min(l1,l2);i++)
	{
		if(x.name[i]==y.name[i]) continue;
		if(x.name[i]<y.name[i]) return true;
		if(x.name[i]>y.name[i]) return false;
	}
	if(l1<l2) return true;
	return false; 
}
int main()
{
	int o;
	n=read(),m=read();
	while(cin>>s)
	{
		tot++;
		a[tot].name=s;
		for(int k=1;k<=n;k++)
		{
			int x=0,f=1;
			cin>>s;int l=strlen(s),i=0;if(s[i]=='-') f=-1,i++;
			while(s[i]>='0'&&s[i]<='9') x=x*10+s[i]-48,i++;
			x*=f;
			if(x>0) {
				a[tot].x++;
				a[tot].t+=x;
				if(s[i]=='('){
					i++;x=0;
					while(s[i]>='0'&&s[i]<='9') x=x*10+s[i]-48,i++;
					a[tot].t+=x*m;i++;
				}
			}
		}
	}
	sort(a+1,a+tot+1,cmp);
	for(int i=1;i<=tot;i++)
	{
		cout<<std::left<<setw(10)<<a[i].name<<" ";
		cout<<std::right<<setw(2)<<a[i].x<<" "<<setw(4)<<a[i].t<<endl;
	}
	return 0;
}

总结:C++ 编译器是VC++,用std:cin或者std:cout输出string时要引用 string库,这种输入一行多个数据的可以考虑分开输入,不要一行全读进去,因为可能会有奇奇怪怪的字符…然后就被卡了

  1. C - 瑞神打牌

瑞神HRZ因为疫情在家闲得无聊,同时他又非常厉害,所有的课对他来说都是水一水就能拿A+,所以他无聊,找来了另外三个人:咕咕东,腾神以及zjm来打牌(天下苦瑞神久矣)。
显然,牌局由四个人构成,围成一圈。我们称四个方向为北 东 南 西。对应的英文是North,East,South,West。游戏一共由一副扑克,也就是52张构成。开始,我们指定一位发牌员(东南西北中的一个,用英文首字母标识)开始发牌,发牌顺序为顺时针,发牌员第一个不发自己,而是发他的下一个人(顺时针的下一个人)。这样,每个人都会拿到13张牌。
现在我们定义牌的顺序,首先,花色是(梅花)<(方片)<(黑桃)<(红桃),(输入时,我们用C,D,S,H分别表示梅花,方片,黑桃,红桃,即其单词首字母)。对于牌面的值,我们规定2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < T < J < Q < K < A。
现在你作为上帝,你要从小到大排序每个人手中的牌,并按照给定格式输出。(具体格式见输出描述和样例输出)。
Input
输入包含多组数据
每组数据的第一行包含一个大写字符,表示发牌员是谁。如果该字符为‘#’则表示输入结束。
接下来有两行,每行有52个字符,表示了26张牌,两行加起来一共52张牌。每张牌都由两个字符组成,第一个字符表示花色,第二个字符表示数值。
Output
输出多组数据发牌的结果,每组数据之后需要额外多输出一个空行!!!!!
每组数据应该由24行的组成,输出按照顺时针方向,始终先输出South Player的结果,每位玩家先输出一行即玩家名称(东南西北),接下来五行,第一行和第五行输出固定格式(见样例),第二行和第四行按顺序和格式输出数值(见样例),第三行按顺序和格式输出花色(见样例)。

思路:模拟题,输出有点鬼畜。一开始搞一个偏移量,然后模拟发牌过程,对于每一个人的牌排一个序,按输出规则输出即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#define LL long long
using namespace std;
string s,t;
struct da{char a,b;int x,y;}a[14],b[14],c[14],d[14];
int l1,l2,l3,l4;
int C(char ch)
{
	if(ch=='C') return 1;
	if(ch=='D') return 2;
	if(ch=='S') return 3;
	if(ch=='H') return 4;
}
int B(char ch)
{
	if(ch>='0'&&ch<='9') return ch-48;
	if(ch=='T') return 10;
	if(ch=='J') return 11;
	if(ch=='Q') return 12;
	if(ch=='K') return 13;
	if(ch=='A') return 14;
}
int cmp(const da &x,const da &y)
{
	int a=C(x.a),b=C(y.a);
	if(a!=b) return a<b;
	a=B(x.b),b=B(y.b);
	if(a!=b) return a<b;
	return a;
}
int main()
{
	char ch;int x;
	while(cin>>ch)
	{
		if(ch=='#') break;
		if(ch=='N') x=1;
		if(ch=='E') x=2;
		if(ch=='S') x=3;
		if(ch=='W') x=0;
		cin>>s;cin>>t;
		s+=t;l1=l2=l3=l4=0;
		int l=s.length(),y=x+1;
		for(int i=0;i<l;i+=2)
		{
			
			if(y==1) a[++l1].a=s[i],a[l1].b=s[i+1];
			if(y==2) b[++l2].a=s[i],b[l2].b=s[i+1];
			if(y==3) c[++l3].a=s[i],c[l3].b=s[i+1];
			if(y==4) d[++l4].a=s[i],d[l4].b=s[i+1];
			y=y%4+1;
		}
		
		sort(a+1,a+14,cmp);sort(b+1,b+14,cmp);
		sort(c+1,c+14,cmp);sort(d+1,d+14,cmp);
		printf("South player:\n");
		printf("+---+---+---+---+---+---+---+---+---+---+---+---+---+\n");
		for(int i=1;i<=13;i++)
		{
			printf("|%c %c",c[i].b,c[i].b);
		}
		printf("|\n");
		for(int i=1;i<=13;i++)
		{
			printf("| %c ",c[i].a);
		}
		printf("|\n");
				for(int i=1;i<=13;i++)
		{
			printf("|%c %c",c[i].b,c[i].b);
		}
		printf("|\n");
		printf("+---+---+---+---+---+---+---+---+---+---+---+---+---+\n");
		printf("West player:\n");
		printf("+---+---+---+---+---+---+---+---+---+---+---+---+---+\n");
		for(int i=1;i<=13;i++)
		{
			printf("|%c %c",d[i].b,d[i].b);
		}
		printf("|\n");
		for(int i=1;i<=13;i++)
		{
			printf("| %c ",d[i].a);
		}
		printf("|\n");
				for(int i=1;i<=13;i++)
		{
			printf("|%c %c",d[i].b,d[i].b);
		}
		printf("|\n");
		printf("+---+---+---+---+---+---+---+---+---+---+---+---+---+\n");
		printf("North player:\n");
		printf("+---+---+---+---+---+---+---+---+---+---+---+---+---+\n");
		for(int i=1;i<=13;i++)
		{
			printf("|%c %c",a[i].b,a[i].b);
		}
		printf("|\n");
		for(int i=1;i<=13;i++)
		{
			printf("| %c ",a[i].a);
		}
		printf("|\n");
				for(int i=1;i<=13;i++)
		{
			printf("|%c %c",a[i].b,a[i].b);
		}
		printf("|\n");
		printf("+---+---+---+---+---+---+---+---+---+---+---+---+---+\n");
		printf("East player:\n");
		printf("+---+---+---+---+---+---+---+---+---+---+---+---+---+\n");
		for(int i=1;i<=13;i++)
		{
			printf("|%c %c",b[i].b,b[i].b);
		}
		printf("|\n");
		for(int i=1;i<=13;i++)
		{
			printf("| %c ",b[i].a);
		}printf("|\n");
		for(int i=1;i<=13;i++)
		{
			printf("|%c %c",b[i].b,b[i].b);
		}
		
		printf("|\n");
		printf("+---+---+---+---+---+---+---+---+---+---+---+---+---+\n");
		printf("\n");
	}
	return 0;
}

思路:不要急着交题,多注意输出,避免PE…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章