清華機試真題

題目感覺比較模式,中規中矩,但是很容易超時或者是有些複雜情況覆蓋不到

進制轉換

題目描述
將一個長度最多爲30位數字的十進制非負整數轉換爲二進制數輸出。
輸入描述:
多組數據,每行爲一個長度不超過30位的十進制非負整數。
(注意是10進制數字的個數可能有30個,而非30bits的整數)
輸出描述:
每行輸出對應的二進制數。
示例1 
輸入
複製
0
1
3
8
輸出
複製
0
1
11
1000

 數字長度過長,long long 類型也無法存儲,使用字符串存儲

#include<iostream>
#include<stdio.h>
#include<string>
using namespace std;

string div2(string input){
//	cout<<"div:"<<input<<endl;
	int rmd=0;
	int shang=0;
	string res;
	for(int i=0;i<input.size();i++){
		shang=(rmd*10+input[i]-'0')/2;
		res.push_back(shang+'0');
		rmd=(rmd*10+input[i]-'0')%2;
	}
	while(res.size()>0){
		if(res[0]=='0')
			res.erase(res.begin());
		else
			break;
	}
//	cout<<"div2"<<endl;
	if(res.size()==0){
		return "0";
	}
	
	return res;
}

char rmd2(string input){
//	cout<<"rmd:"<<input<<endl;
	if((input[input.size()-1]-'0')%2==0){
		return '0';
	}
	else{
		return '1';
	}
}

string getres(string input){
//	cout<<"getres:"<<input<<endl;
	string res;
	char rmd;
	while(input!="0"){
		rmd=rmd2(input);
		input=div2(input);
		res.insert(res.begin(),rmd);
	}
	if(res.size()==0)
		return "0";
	return res;
}

int main(){
	string input;
	while(cin>>input){
		cout<<getres(input)<<endl;
	}
}

成績排序

查找和排序 
題目:輸入任意(用戶,成績)序列,可以獲得成績從高到低或從低到高的排列,相同成績
都按先錄入排列在前的規則處理。 
示例:
jack      70
peter     96
Tom       70
smith     67 
從高到低  成績 
peter     96 
jack      70 
Tom       70 
smith     67 
從低到高 
smith     67 
jack      70 
Tom      70 
peter     96 
輸入描述:
輸入多行,先輸入要排序的人的個數,然後輸入排序方法0(降序)或者1(升序)再分別輸入他們的名字和成績,以一個空格隔開
輸出描述:
按照指定方式輸出名字和成績,名字和成績之間以一個空格隔開
示例1 
輸入
複製
3
0
fang 90
yang 50
ning 70
輸出
複製
fang 90
ning 70
yang 50

排序,結構體定義,重載操作符,注意審題

#include<vector>
#include<algorithm>
using namespace std;

struct record{
	string name;
	int score;
	int count;
	int asc;
	
	bool operator < (const record& r) const{
		if(score!=r.score)
			return score<r.score;
		else{
			if(asc==0)
				return count>r.count;
			else
				return count<r.count;
		}
	}
};


int main(){
	int n,asc;
	int count;
	
	while(cin>>n){
		count=0;
	cin>>asc;
	vector<record> re;
	while(n--){
		record temp;
		cin>>temp.name;
		cin>>temp.score;
		temp.count=count;
		temp.asc=asc;
		re.push_back(temp);
		count++;
	}
	sort(re.begin(),re.begin()+re.size());
	if(asc==1){
		for(int i=0;i<re.size();i++){
			cout<<re[i].name<<" "<<re[i].score<<endl;
		}
	}
	else if(asc==0){
		for(int i=re.size()-1;i>=0;i--){
			cout<<re[i].name<<" "<<re[i].score<<endl;
		}
	}
}
}

約數的個數

輸入n個整數,依次輸出每個數的約數的個數
輸入描述:
輸入的第一行爲N,即數組的個數(N<=1000)
接下來的1行包括N個整數,其中每個數的範圍爲(1<=Num<=1000000000)
當N=0時輸入結束。
輸出描述:
可能有多組輸入數據,對於每組輸入數據,
輸出N行,其中每一行對應上面的一個數的約數的個數。
示例1 
輸入
複製
5
1 3 4 6 12
輸出
複製
1
2
3
4
6

數的範圍很大,直接暴力會超時,轉化爲開方

#include<iostream>
using namespace std;

int main(){
    int n;
    int tmp;
    while(cin>>n){
        while(n--){
            cin>>tmp;
            int sum=0;
            int i;
            for(i=1;i*i<tmp;i++){
            	if(tmp%i==0)
            		sum+=2;
			}
			if(i*i==tmp)
				sum++;
			cout<<sum<<endl;
        }
    }
}

代理服務器

題目描述
    使用代理服務器能夠在一定程度上隱藏客戶端信息,從而保護用戶在互聯網上的隱私。我們知道n個代理服務器的IP地址,現在要用它們去訪問m個服務器。這 m 個服務器的 IP 地址和訪問順序也已經給出。系統在同一時刻只能使用一個代理服務器,並要求不能用代理服務器去訪問和它 IP地址相同的服務器(不然客戶端信息很有可能就會被泄露)。在這樣的條件下,找到一種使用代理服務器的方案,使得代理服務器切換的次數儘可能得少。
輸入描述:
    每個測試數據包括 n + m + 2 行。
    第 1 行只包含一個整數 n,表示代理服務器的個數。
    第 2行至第n + 1行每行是一個字符串,表示代理服務器的 IP地址。這n個 IP地址兩兩不相同。
    第 n + 2 行只包含一個整數 m,表示要訪問的服務器的個數。
    第 n + 3 行至第 n + m + 2 行每行是一個字符串,表示要訪問的服務器的 IP 地址,按照訪問的順序給出。
    每個字符串都是合法的IP地址,形式爲“xxx.yyy.zzz.www”,其中任何一部分均是0–255之間的整數。輸入數據的任何一行都不包含空格字符。
     其中,1<=n<=1000,1<=m<=5000。
輸出描述:
    可能有多組測試數據,對於每組輸入數據, 輸出數據只有一行,包含一個整數s,表示按照要求訪問服務器的過程中切換代理服務器的最少次數。第一次使用的代理服務器不計入切換次數中。若沒有符合要求的安排方式,則輸出-1。
示例1 
輸入
複製
3
166.111.4.100
162.105.131.113
202.112.128.69
6
72.14.235.104
166.111.4.100
207.46.19.190
202.112.128.69
162.105.131.113
118.214.226.52
輸出
複製
1

動態規劃思想

#include<iostream>
#include<vector>
using namespace std;

int main(){
	int n;
	int MAX=6000;
	while(cin>>n){
		vector<string> agent(n);
		for(int i=0;i<n;i++){
			cin>>agent[i];
		} 
		int m;
		cin>>m;
		vector<string> server(m);
		for(int i=0;i<m;i++){
			cin>>server[i];
		}
		vector<vector<int> > dis(m+1);
		for(int i=0;i<m+1;i++){
			dis[i].resize(n);
			for(int j=0;j<n;j++){
				dis[i][j]=MAX;
			} 
		}
		for(int i=m-1;i>=0;i--){
			for(int j=0;j<n;j++){
				if(server[i]==agent[j]){
					dis[i][j]=0;
				}
				else{
					dis[i][j]=dis[i+1][j]+1;
				}
			}
		}
		int count=0;
		int index=0;
		int jndex=0;
		int max=0;
		for(int i=0;i<n;i++){
			if(max<dis[0][i]){
				index=i;
				max=dis[0][i];
			}
		}
		if(max==0){
			cout<<"-1"<<endl;
			break;
		}
		jndex=jndex+dis[0][index];
		while(jndex<m){
			max=0;
			index=0;
			for(int i=0;i<n;i++){
				if(max<dis[jndex][i]){
					index=i;
					max=dis[jndex][i];
				}
			}
			if(max==0){
				count=-1;
				break;
			}
			jndex=jndex+dis[jndex][index];
			count++;
		}
		cout<<count<<endl;
	} 
	
} 

手機鍵盤

題目描述
按照手機鍵盤輸入字母的方式,計算所花費的時間 如:a,b,c都在“1”鍵上,輸入a只需要按一次,輸入c需要連續按三次。 如果連續兩個字符不在同一個按鍵上,則可直接按,如:ad需要按兩下,kz需要按6下 如果連續兩字符在同一個按鍵上,則兩個按鍵之間需要等一段時間,如ac,在按了a之後,需要等一會兒才能按c。 現在假設每按一次需要花費一個時間段,等待時間需要花費兩個時間段。 現在給出一串字符,需要計算出它所需要花費的時間。
輸入描述:
一個長度不大於100的字符串,其中只有手機按鍵上有的小寫字母
輸出描述:
輸入可能包括多組數據,對於每組數據,輸出按出Input所給字符串所需要的時間
示例1 
輸入
複製
bob
www
輸出
複製
7
7

能記起九宮格是什麼樣就行了

#include<iostream>
#include<vector>
using namespace std;

int main(){
	vector<int>pos(26);
	vector<int>time(26);
	pos[0]=2;
	time[0]=1;
	pos[1]=2;
	time[1]=2;
	pos[2]=2;
	time[2]=3;
	pos[3]=3;
	time[3]=1;
	pos[4]=3;
	time[4]=2;
	pos[5]=3;
	time[5]=3;
	pos[6]=4;
	time[6]=1;
	pos[7]=4;
	time[7]=2;
	pos[8]=4;
	time[8]=3;
	pos[9]=5;
	time[9]=1;
	pos[10]=5;
	time[10]=2;
	pos[11]=5;
	time[11]=3;
	pos[12]=6;
	time[12]=1;
	pos[13]=6;
	time[13]=2;
	pos[14]=6;
	time[14]=3;
	pos[15]=7;
	time[15]=1;
	pos[16]=7;
	time[16]=2;
	pos[17]=7;
	time[17]=3;
	pos[18]=7;
	time[18]=4;
	pos[19]=8;
	time[19]=1;
	pos[20]=8;
	time[20]=2;
	pos[21]=8;
	time[21]=3;
	pos[22]=9;
	time[22]=1;
	pos[23]=9;
	time[23]=2;
	pos[24]=9;
	time[24]=3;
	pos[25]=9;
	time[25]=4;
	string s;
	while(cin>>s){
		int res=0;
		int pre=-1;
		for(int i=0;i<s.size();i++){
			int ii=s[i]-'a';
			res+=time[ii];
			if(pos[ii]==pre) res+=2;
			pre=pos[ii];
		}
		cout<<res<<endl;
	}
}

整數拆分1

題目描述
一個整數總可以拆分爲2的冪的和,例如: 7=1+2+4 7=1+2+2+2 7=1+1+1+4 7=1+1+1+2+2 7=1+1+1+1+1+2 7=1+1+1+1+1+1+1 總共有六種不同的拆分方式。 再比如:4可以拆分成:4 = 4,4 = 1 + 1 + 1 + 1,4 = 2 + 2,4=1+1+2。 用f(n)表示n的不同拆分的種數,例如f(7)=6. 要求編寫程序,讀入n(不超過1000000),輸出f(n)%1000000000。
輸入描述:
每組輸入包括一個整數:N(1<=N<=1000000)。
輸出描述:
對於每組數據,輸出f(n)%1000000000。
示例1 
輸入
複製
7
輸出
複製
6

題目的意思是將整數n拆分成2的冪,一共有多少種拆分方法,思路爲動態規劃,那麼關鍵就是遞歸方程如何寫!!

考慮以下情況

  • n爲奇數時,可以拆分的情況之後在n-1的拆分情況上加1,即 f(n)=f(n-1)
  • n爲偶數時,對n進行拆分,按照可不可以拆分出1劃分
    • 可以拆分出1,f(n-1)
    • 不可以拆分出1,也就是將n/2拆分的結果每個乘2,即f(n/2)
    • f(n)=f(n-1)+f(n/2)
  • 起始爲 f(0)=0,f(1)=1,f(2)=2
#include<stdio.h>
int main(){
    int dp[1000001],num,i;
    dp[0]=0;
    dp[1]=1;
    dp[2]=2;
    for(i=3;i<=1000000;i++){
        dp[i]=0;
        if(i&1)
            dp[i]=(dp[i-1])%1000000000;
        else
            dp[i]=(dp[i-1]+dp[i/2])%1000000000;
    }
    while(scanf("%d",&num)!=EOF)
        printf("%d\n",dp[num]);
}

關於數組分配的空間是不是太大這個問題很玄學


數字拆分2

這道題爲看到的另一個經典的動態規劃題目

輸入n,k;輸出將n拆分爲最大值爲k的組合的個數

如n=5,k=5時輸出結果爲5

思路如下

  • 當n=k時,f(n,k)=f(n,k-1)+1。加的1時n=k
  • 當n<k時,f(n,k)=f(n,n)
  • 當n>k時,考慮能不能拆分出k
    • f(n,k)=f(n-k,k)+f(n,k-1)
  • 初始條件爲 f(1,i)=1,f(i,1)=1
#include<stdio.h>
#include<iostream>
#include<vector>
using namespace std;

int main(){
	int n,k;
	while(cin>>n){
		cin>>k;
		vector<vector <int> > dp(n+1);
		for(int i=0;i<=n;i++){
			dp[i].resize(k+1);
			for(int j=0;j<=k;j++){
				dp[i][j]=0;
				if(j==1) dp[i][j]=1;
				if(i==1) dp[i][j]=1;
			}
		}
		for(int i=2;i<=n;i++){
			for(int j=2;j<=k;j++){
				if(i==j) dp[i][j]=dp[i][j-1]+1;
				else if(i<j) dp[i][j]=dp[i][i];
				else{
					dp[i][j]=dp[i-j][j]+dp[i][j-1];
				}
			}
		}
	}
} 

 

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