程序設計思維與實踐 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…

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