北大百炼

护林员盖房子

总时间限制:

1000ms

内存限制:

65536kB

描述

在一片保护林中,护林员想要盖一座房子来居住,但他不能砍伐任何树木。
现在请你帮他计算:保护林中所能用来盖房子的矩形空地的最大面积。

输入

保护林用一个二维矩阵来表示,长宽都不超过20(即<=20)。
第一行是两个正整数m,n,表示矩阵有m行n列。
然后是m行,每行n个整数,用1代表树木,用0表示空地。

输出

一个正整数,表示保护林中能用来盖房子的最大矩形空地面积。

样例输入

4 5
0 1 0 1 1
0 1 0 0 1
0 0 0 0 0
0 1 1 0 1

样例输出

5

提示

子矩阵边长可以为1,也就是说:
0 0 0 0 0
依然是一个可以盖房子的子矩阵。

//护林员盖房子

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

int main(){
	int row,colum;
	cin >> row;  //行 
	cin >> colum;  //列
	vector<vector<int> > num;  //这里需要注意两个 < 之间需要有空格,否则的话会当做 >> 处理,会报错 
	vector<vector<int> > left;
	vector<vector<int> > up;
	num.resize(row);
	left.resize(row);
	up.resize(row);
	for(int i=0;i<row;i++){
		num[i].resize(colum);
		left[i].resize(colum);
		up[i].resize(colum);
	}
	 
	for(int i=0;i<row;i++){
		for(int j=0;j<colum;j++)
			cin>>num[i][j];
	}
	
	for(int i=0;i<row;i++){
		for(int j=0;j<colum;j++){
			if(num[i][j]==1){
				left[i][j]=0;
				up[i][j]=0;
			}
			else{
				if(i==0&&j==0){
					up[i][j]=1;
					left[i][j]=1;
				}
				else{
					if(i==0){
						up[i][j]=1;
						left[i][j]=left[i][j-1]+1;
					}
					else if(j==0){
						up[i][j]=up[i-1][j]+1;
						left[i][j]=1;
					}
					else{
						up[i][j]=up[i-1][j]+1;
						left[i][j]=left[i][j-1]+1;
					}
				}
			}
		}
	}
	
	int max=0;
	for(int i=0;i<row;i++){
		for(int j=0;j<colum;j++){
			if(left[i][j]==0||up[i][j]==0){
				continue;
			}
			else{
				int min=up[i][j];
				for(int k=1;k<left[i][j];k++){
					min=min<up[i][j-k]?min:up[i][j-k];
				}
				int temp=min*left[i][j];
				max=max>temp?max:temp;
			}
		}
	}
	cout << max;
	return 0;	
} 

整个题目的思路是动态规划,维护两个数组。问题的关键是要组成矩形,所以横竖都要是有空间的,做题的时候现在纸上想清楚了再说吧。

注意输入的部分,定义二维vector的部分,初始化两个vector的部分,以及 >和>之间要有空格。


方便记忆的电话号码

总时间限制:

2000ms

内存限制:

65536kB

描述

英文字母(除Q和Z外)和电话号码存在着对应关系,如下所示:

A,B,C -> 2

D,E,F -> 3

G,H,I -> 4

J,K,L -> 5

M,N,O -> 6

P,R,S -> 7

T,U,V -> 8

W,X,Y -> 9

标准的电话号码格式是xxx-xxxx,其中x表示0-9中的一个数字。有时为了方便记忆电话号码,我们会将电话号码的数字转变为英文字母,如把263-7422记成America。有时,我们还加上“-”作为分隔符,如把449-6753记成Hi-World。当然,我们未必要将所有的数字都转变为字母,比如474-6635可以记成iPhone-5。

总之,一个方便记忆的电话号码由数字和除Q、Z外的英文字母组成,并且可以在任意位置插入任意多的“-”符号。

现在 ,我们有一个列表,记录着许多方便记忆的电话号码。不同的方便记忆的电话号码可能对应相同的标准号码,你的任务就是找出它们。

 

输入

第一行是一个正整数n(n <= 100000),表示列表中的电话号码数。
其后n行,每行是一个方便记忆的电话号码,它由数字和除Q、Z外的英文字母、“-”符号组成,其中数字和字母的总数一定为7,字符串总长度不超过200。

输出

输出包括若干行,每行包括一个标准电话号码(xxx-xxxx)以及它重复出现的次数k(k >= 2),中间用空格分隔。输出的标准电话号码需按照升序排序。

如果没有重复出现的标准电话号码,则输出一行“No duplicates.”。

样例输入

12
4873279
ITS-EASY
888-4567
3-10-10-10
888-GLOP
TUT-GLOP
967-11-11
310-GINO
F101010
888-1200
-4-8-7-3-2-7-9-
487-3279

样例输出

310-1010 2
487-3279 4
888-4567 3 
//方便记忆的电话号码

#include<iostream>
#include<map>
#include<string>
using namespace std; 

void inital(map<char,char> &table){
	table['A']='2';
	table['B']='2';
	table['C']='2';
	table['D']='3';
	table['E']='3';
	table['F']='3';
	table['G']='4';
	table['H']='4';
	table['I']='4';
	table['J']='5';
	table['K']='5';
	table['L']='5';
	table['M']='6';
	table['N']='6';
	table['O']='6';
	table['P']='7';
	table['R']='7';
	table['S']='7';
	table['T']='8';
	table['U']='8';
	table['V']='8';
	table['W']='9';
	table['X']='9';
	table['Y']='9';
}

string dealInput(string s,map<char,char> table){
	string res="";
	for(int i=0;i<s.size();i++){
		if(s[i]>='0'&&s[i]<='9'){
			res.push_back(s[i]);
		} 
		else if(s[i]=='-'){
			continue;
		}
		else if(s[i]>='A'&&s[i]<'Z'&&s[i]!='Q'){
			res.push_back(table[s[i]]);
		}
	}
	return res;
}


int main(){
	map<char,char> table;
	inital(table);
	map<string,int> record;
	int num;
	int count=0;
	cin >> num;
	for(int i=0;i<num;i++){
		string temp;
		cin >> temp;
		temp=dealInput(temp,table);
		if(record.find(temp)==record.end()){
			record[temp]=1;
		}
		else{
			record[temp]+=1;
			count++;
		}
	}
	if(count==0){
		cout<<"No duplicates."<<endl;
	}
	else{
		map<string,int>::iterator iter;
		for(iter=record.begin();iter!=record.end();iter++){
			if(iter->second>1){
				string temp=iter->first;
				cout<<temp.insert(3,"-")<<" "<<iter->second<<endl;
//				cout<<temp<<" "<<iter->second<<endl;
			}
		}
	}
	
}
 

主要是使用map进行映射。

需要复习一下map的用法以及string的用法。


E:The Suspects

总时间限制:

1000ms

内存限制:

65536kB

描述

Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. To minimize transmission to others, the best strategy is to separate the suspects from others.
In the Not-Spreading-Your-Sickness University (NSYSU), there are many student groups. Students in the same group intercommunicate with each other frequently, and a student may join several groups. To prevent the possible transmissions of SARS, the NSYSU collects the member lists of all student groups, and makes the following rule in their standard operation procedure (SOP).
Once a member in a group is a suspect, all members in the group are suspects.
However, they find that it is not easy to identify all the suspects when a student is recognized as a suspect. Your job is to write a program which finds all the suspects.

输入

The input file contains several cases. Each test case begins with two integers n and m in a line, where n is the number of students, and m is the number of groups. You may assume that 0 < n <= 30000 and 0 <= m <= 500. Every student is numbered by a unique integer between 0 and n−1, and initially student 0 is recognized as a suspect in all the cases. This line is followed by m member lists of the groups, one line per group. Each line begins with an integer k by itself representing the number of members in the group. Following the number of members, there are k integers representing the students in this group. All the integers in a line are separated by at least one space.
A case with n = 0 and m = 0 indicates the end of the input, and need not be processed.

输出

For each case, output the number of suspects in one line.

样例输入

100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
200 2
1 5
5 1 2 3 4 5
1 0
0 0

样例输出

4
1
1

来源

Asia Kaohsiung 2003

#include<iostream>
#include<stdlib.h>
#include<vector>
#include<sstream>
#include<stdio.h> 
using namespace std;

void init(vector<int> &pre,vector<int> &sum){
	for(int i=0;i<pre.size();i++){
		pre[i]=i;
		sum[i]=1;
	}
}

int getRoot(int i,vector<int> pre){
	while(pre[i]!=i){
		i=pre[i];
	}
	return i;
} 

void merge(vector<int>&pre,vector<int>&sum,int one,int two){
	int x=getRoot(one,pre);
	int y=getRoot(two,pre);
	if(x!=y){
		pre[y]=x;
		sum[x]+=sum[y];
	}
}


int main(){
	int m,n;
	while(true){
		scanf("%d %d",&m,&n);
		if(m==0&&n==0) return 0;
		
		vector<int> pre;
		vector<int> sum;
		pre.resize(m);
		sum.resize(m);
		
		init(pre,sum);
		
		for(int i=0;i<n;i++){
			int size;
			scanf("%d",&size);
			int one,two;
			scanf("%d",&one);
			for(int j=0;j<size-1;j++){
				scanf("%d",&two);
				merge(pre,sum,one,two);
			}
		}
		cout<<"sum:"<<sum[getRoot(0,pre)]<<endl;
	}
} 

做题之后的感想,百炼真的是比较难,哭了

1.处理输入

C++中使用cin的话好像不是很容易来处理,不,突然发现cin也是可以从输入台获取一整行的输入,像这样

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

int main(){
	int a,b;
	cin>>a;   //输入 1 2,输出1 
	cout<<a<<endl;
	return 0;
}

或者是用 scanf 也可以获取一个一个的数字。

2.并查集 经典题目

使用pre存放当前节点的前驱节点,使用sum存放以当前节点为前驱节点的节点的个数。

getRoot()函数的作用是获取当前节点的根节点,merge的作用是将两个联通的节点合并,(在根节点处合并),最终需要返回与0相联通的节点的个数,以0的根节点为根节点的所有节点都是与0相联通的,最终返回sum[getRoot(0)]


Stockbroker Grapevine

总时间限制:

1000ms

内存限制:

65536kB

描述

Stockbrokers are known to overreact to rumours. You have been contracted to develop a method of spreading disinformation amongst the stockbrokers to give your employer the tactical edge in the stock market. For maximum effect, you have to spread the rumours in the fastest possible way.

Unfortunately for you, stockbrokers only trust information coming from their "Trusted sources" This means you have to take into account the structure of their contacts when starting a rumour. It takes a certain amount of time for a specific stockbroker to pass the rumour on to each of his colleagues. Your task will be to write a program that tells you which stockbroker to choose as your starting point for the rumour, as well as the time it will take for the rumour to spread throughout the stockbroker community. This duration is measured as the time needed for the last person to receive the information.

输入

Your program will input data for different sets of stockbrokers. Each set starts with a line with the number of stockbrokers. Following this is a line for each stockbroker which contains the number of people who they have contact with, who these people are, and the time taken for them to pass the message to each person. The format of each stockbroker line is as follows: The line starts with the number of contacts (n), followed by n pairs of integers, one pair for each contact. Each pair lists first a number referring to the contact (e.g. a '1' means person number one in the set), followed by the time in minutes taken to pass a message to that person. There are no special punctuation symbols or spacing rules.

Each person is numbered 1 through to the number of stockbrokers. The time taken to pass the message on will be between 1 and 10 minutes (inclusive), and the number of contacts will range between 0 and one less than the number of stockbrokers. The number of stockbrokers will range from 1 to 100. The input is terminated by a set of stockbrokers containing 0 (zero) people.
 

输出

For each set of data, your program must output a single line containing the person who results in the fastest message transmission, and how long before the last person will receive any given message after you give it to this person, measured in integer minutes.
It is possible that your program will receive a network of connections that excludes some persons, i.e. some people may be unreachable. If your program detects such a broken network, simply output the message "disjoint". Note that the time taken to pass the message from person A to person B is not necessarily the same as the time taken to pass it from B to A, if such transmission is possible at all.

样例输入

3
2 2 4 3 5
2 1 2 3 6
2 1 2 2 2
5
3 4 4 2 8 5 3
1 5 8
4 1 6 4 10 2 7 5 2
0
2 2 5 1 5
0

样例输出

3 2
3 10
#include<stdio.h>
#include<iostream>
#include<vector>
using namespace std;

int main(){
	while(true){
		int ns;
		vector<vector<int> > cost;
		vector<vector<int> > record; 
		cin>>ns;
		if(ns==0) return 0;
		cost.resize(ns);
		record.resize(ns);
		for(int i=0;i<ns;i++){
			cost[i].resize(ns);
			record[i].resize(ns);
			for(int j=0;j<ns;j++){
				if(i==j) cost[i][j]=0;
				else cost[i][j]=11;
			}
		}
		for(int i=0;i<ns;i++){
			int temp;
			cin>>temp;
			for(int j=0;j<temp;j++){
				int s,t;
				cin>>s;
				cin>>t;
				cost[i][s-1]=t;
			}
		}
		//求当前节点到其他所有节点的最短路径?
		for(int i=0;i<ns;i++){
			for(int j=0;j<ns;j++){
				cout<<cost[i][j]<<" ";
			}
			cout<<endl;
		}
		
		int start,time;
		time=INT_MAX;
		
		for(int i=0;i<ns;i++){//对于编号为i的节点 
		cout<<"---------------"<<endl;
			record[0]=cost[i];
			for(int j=1;j<ns-1;j++){  //处理表的每一行 
				for(int k=0;k<ns;k++){  //每一行的每个单元 
					int temp=record[j-1][k];
					for(int m=0;m<ns;m++){
						temp=temp<record[j-1][m]+cost[m][k]?temp:record[j-1][m]+cost[m][k];
					}
					record[j][k]=temp;
				}
			}
			int temptime=record[ns-2][0];
			for(int i=1;i<ns;i++){
				temptime=temptime>record[ns-2][i]?temptime:record[ns-2][i];
				cout<<"temp:"<<temptime<<endl;
			}
			if(temptime<time){
				start=i+1;
				time=temptime;
			}
		}
		if(time>10){
			cout<<"disjoint"<<endl;
		}else{
			cout<<start<<" "<<time<<endl;
		}
	}
}

有点类似有向图的最短路径问题,但是有一个区别是谣言传播是可以并行传播的,所以从A开始将谣言传播的时间为从A传播到其他节点的时间的最大值,问题也就转化为带权图中从一个节点到另一个节点的最短距离。可以使用dijistra算法或者是Bellman-Ford算法。

使用上面的方法会有问题,临界值设置的有问题

以下代码是通过的

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

int main(){
	while(true){
		int ns;
		vector<vector<int> > cost;  //i+1到j+1传播消息的时间 
		vector<vector<int> > record;   //dp数组 
		cin>>ns;
		if(ns==0) return 0;
		cost.resize(ns);
		record.resize(ns);
		for(int i=0;i<ns;i++){
			cost[i].resize(ns);
			record[i].resize(ns);
			for(int j=0;j<ns;j++){
				if(i==j) cost[i][j]=0;
				else cost[i][j]=0x3f3f3f3f;
			}
		}
		for(int i=0;i<ns;i++){
			int temp;
			cin>>temp;
			for(int j=0;j<temp;j++){
				int s,t;
				cin>>s;
				cin>>t;
				cost[i][s-1]=t;
			}
		}
//		//求当前节点到其他所有节点的最短路径?
//		for(int i=0;i<ns;i++){
//			for(int j=0;j<ns;j++){
//				cout<<cost[i][j]<<" ";
//			}
//			cout<<endl;
//		}
		
		int start,time;
		time=0x3f3f3f3f;
		
		for(int i=0;i<ns;i++){//对于编号为i的节点 
//		cout<<"---------------"<<endl;
			record[0]=cost[i];
			for(int j=1;j<ns-1;j++){  //处理表的每一行 
				for(int k=0;k<ns;k++){  //每一行的每个单元 
					int temp=record[j-1][k];
					for(int m=0;m<ns;m++){
						temp=temp<record[j-1][m]+cost[m][k]?temp:record[j-1][m]+cost[m][k];
					}
					record[j][k]=temp;
				}
			}
			int temptime=record[ns-2][0];
			for(int j=1;j<ns;j++){  //传递的最长时间 
				temptime=temptime>record[ns-2][j]?temptime:record[ns-2][j];
//				cout<<"temp:"<<temptime<<endl;
			}
			if(temptime<time){
				start=i+1;
				time=temptime;
			}
		}
		if(time==0x3f3f3f3f){
			cout<<"disjoint"<<endl;
		}else{
			cout<<start<<" "<<time<<endl;
		}
	}
}

在无穷的表示那里有问题,MAX_INT编译器不识别,另外最开始与11进行比较也是错误的,100个人,很有可能会超过11的


Jumping Cows

总时间限制:

1000ms

内存限制:

65536kB

描述

Farmer John's cows would like to jump over the moon, just like the cows in their favorite nursery rhyme. Unfortunately, cows can not jump.

The local witch doctor has mixed up P (1 <= P <= 150,000) potions to aid the cows in their quest to jump. These potions must be administered exactly in the order they were created, though some may be skipped.

Each potion has a 'strength' (1 <= strength <= 500) that enhances the cows' jumping ability. Taking a potion during an odd time step increases the cows' jump; taking a potion during an even time step decreases the jump. Before taking any potions the cows' jumping ability is, of course, 0.

No potion can be taken twice, and once the cow has begun taking potions, one potion must be taken during each time step, starting at time 1. One or more potions may be skipped in each turn.

Determine which potions to take to get the highest jump.

输入

* Line 1: A single integer, P

* Lines 2..P+1: Each line contains a single integer that is the strength of a potion. Line 2 gives the strength of the first potion; line 3 gives the strength of the second potion; and so on.

输出

* Line 1: A single integer that is the maximum possible jump.

样例输入

8
7
2
1
8
4
3
5
6

样例输出

17
///jump cow
#include<iostream>
#include<stdio.h>
#include<vector>
using namespace std;

int main(){
	int n;
	cin>>n;
	vector<int> en;
	en.resize(n+1);
	en[0]=0;
	for(int i=1;i<n+1;i++){
		cin>>en[i];
	}
	
	int res=0;
	bool odd=true;  //第一个是奇数
	
	int temp=en[0];
	for(int i=1;i<n+1;){
		if(odd){  //需要加 
			if(en[i]>en[i-1]){
				cout<<"hhh"<<en[i]<<endl;
				temp=en[i];
				i++;
			}
			else{
				res+=temp;
				cout<<"add:"<<temp<<endl;
				odd=false;
			}
		}else{
			if(en[i]<=en[i-1]){
				temp=en[i];
				i++;
			}
			else{
				res-=temp;
				cout<<"erase:"<<temp<<endl;
				odd=true;
			}
		}
	}
	if(odd){
		res=res+en[n];
	} 
	cout<<res<<endl;
}

因为可以跳过,考虑是贪心算法,题目的意思是从最开始能量是0,跳跃次数也是0,如果跳跃次数为奇数,则加上跳到的位置的能量,否则减掉跳到位置的能量,得到怎么跳能使能量最大。


区间内的真素数

总时间限制:

1000ms

内存限制:

65536kB

描述

找出正整数 M 和 N 之间(N 不小于 M)的所有真素数。

真素数的定义:如果一个正整数 P 为素数,且其反序也为素数,那么 P 就为真素数。
例如,11,13 均为真素数,因为11的反序还是为11,13 的反序为 31 也为素数。

输入

输入两个数 M 和 N,空格间隔,1 <= M <= N <= 100000。

输出

按从小到大输出 M 和 N 之间(包括 M 和 N )的真素数,逗号间隔。如果之间没有真素数,则输出 No。

样例输入

10 35

样例输出

11,13,17,31
#include<iostream>
#include<vector>
#include<map> 

using namespace std;

//判断是n否为素数 考虑能否被2-根号n整除

int convert(int n){
	int temp=0;
	while(n!=0){
		temp=temp*10+n%10;
		n=n/10;
	}
	return temp;
}

bool isTrue(int n){  //判断是否为真素数 
	//cout<<"n:"<<n<<endl;
	if(n==1||n==2){
		return true;
	}
	for(int i=2;i*i<=n;i++){
		if(n%i==0){
			return false;
		}
	}
	int temp=convert(n);
	for(int i=2;i*i<temp;i++){
		if(temp%i==0){
			return false;
		}
	}
	return true;
}

int main(){
	int m,n;
	cin>>m;
	cin>>n;
	
	for(int i=m;i<=n;i++){
		if(isTrue(i)){
			cout<<i<<",";
		}
	}
} 

题目不是很难,反倒是自己有些自作聪明导致做了很久。

首先需要明确素数的定义,只能被1和它本身整除的数为素数,可以尝试从2-根号n看是否能将n整除。

还有就是将一个整数反转,一开始没想明白所以emmm

本来想着用map,但是这样并没有节省时间,如果是30,按照原先的思路判断将它反转过来也就是3是素数,但是30并不是素数,这就导致了最终出现了错误。

总之,看起来简单的题也是不要大意,感觉稳了,那就要更稳。


简单密码

总时间限制:

1000ms

内存限制:

65536kB

描述

Julius Caesar曾经使用过一种很简单的密码。对于明文中的每个字符,将它用它字母表中后5位对应的字符来代替,这样就得到了密文。比如字符A用F来代替。如下是密文和明文中字符的对应关系。

密文
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

明文
V W X Y Z A B C D E F G H I J K L M N O P Q R S T U

你的任务是对给定的密文进行解密得到明文。

你需要注意的是,密文中出现的字母都是大写字母。密文中也包括非字母的字符,对这些字符不用进行解码。

输入

一行,给出密文,密文不为空,而且其中的字符数不超过200。

输出

输出一行,即密文对应的明文。

样例输入

NS BFW, JAJSYX TK NRUTWYFSHJ FWJ YMJ WJXZQY TK YWNANFQ HFZXJX

样例输出

IN WAR, EVENTS OF IMPORTANCE ARE THE RESULT OF TRIVIAL CAUSES
#include<iostream>
using namespace std;

int main(){
	char dict[26]={'V','W','X','Y', 'Z','A' ,'B', 'C', 'D', 'E', 'F',\
	 'G', 'H', 'I', 'J', 'K','L' ,'M', 'N', 'O', 'P', 'Q', 'R' ,'S','T','U' };
	char temp;
	while(temp=cin.get()){
		if(temp>='A'&&temp<='Z'){
			cout<<dict[temp-'A'];
		}
		else if(temp==' '){
			cout<<" ";
		}
		else{
			cout<<temp;
		}
	}
//	string input;
//	while(cin>>input){
//		for(int i=0;i<input.size();i++){
//			if(input[i]>='A'&&input[i]<='Z'){
//				cout<<dict[input[i]-'A'];
//			}
//			else{
//				cout<<input[i];
//			}
//		}
//		cout<<" ";
//	}
}

总觉得这道题目有些简单以致于怀疑自己是否有没考虑到的地方。

需要注意的一点是,当读取单个的字符的时候,使用cin会自动忽略掉空格,所以可以使用 scanf("%c",&temp) 或者是 temp=cin.get()读取单个字符并且不会忽略空格。

在程序中被注释掉的那部分选择读取单个字符导致如果两个字符串之间如果是两个空格的会就会出错。


最佳加法表达式

总时间限制:

1000ms

内存限制:

65536kB

描述

给定n个1到9的数字,要求在数字之间摆放m个加号(加号两边必须有数字),使得所得到的加法表达式的值最小,并输出该值。例如,在1234中摆放1个加号,最好的摆法就是12+34,和为36

输入

有不超过15组数据
每组数据两行。第一行是整数m,表示有m个加号要放( 0<=m<=50)
第二行是若干个数字。数字总数n不超过50,且 m <= n-1

输出

对每组数据,输出最小加法表达式的值

样例输入

2
123456
1
123456
4
12345

样例输出

102
579
15

提示

要用到高精度计算,即用数组来存放long long 都装不下的大整数,并用模拟列竖式的办法进行大整数的加法。

//最佳加法表达式

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

int maxsum=0;

string add(string a,string b){
	//cout<<"add:"<<a<<" "<<b<<endl;
	string res="";
	int fro=0;  //要进位的数
	int lena=a.size();
	int lenb=b.size();
	int len=lena<lenb?lena:lenb;
	for(int i=1;i<=len;i++){
		int aa=a[lena-i]-'0';
		int bb=b[lenb-i]-'0';
		int sum=aa+bb+fro;
		fro=sum/10;
		res.insert(res.begin(),(sum%10)+'0');
	}
	if(lena==lenb){
		if(fro!=0){
			res.insert(res.begin(),fro+'0');
		}
	}
	else if(lena>lenb){
		for(int i=lena-len-1;i>=0;i--){
			int sum=fro+(a[i]-'0');
			fro=sum/10;
			res.insert(res.begin(),(sum%10)+'0');
		}
		if(fro!=0){
			res.insert(res.begin(),fro+'0');
		}
	}
	else if(lenb>lena){
		for(int i=lenb-len-1;i>=0;i--){
			int sum=fro+(b[i]-'0');
			fro=sum/10;
			res.insert(res.begin(),(sum%10)+'0');
		}
		if(fro!=0){
			res.insert(res.begin(),fro+'0');
		}
	}
	return res;
}

bool bigger(string a,string b){  //假设a为无穷大 
	if(a=="a") return true;
	if(b=="a") return false;
	if(a.size()>b.size()) return true;
	else if(a.size()<b.size()) return false;
	else{
		for(int i=0;i<a.size();i++){
			if((a[i]-'0')>(b[i]-'0')) return true;
			else if((a[i]-'0')<(b[i]-'0')) return false;
		}
		return true;
	} 
}

string getdp(vector<vector<string> >& dp,int i,int j,string s){
	string res="a"; 
	for(int k=0;k<j;k++){
		if(dp[i-1][k]!="a"){
			string temp=add(dp[i-1][k],s.substr(k,j-k));
			if(bigger(res,temp)){
				res=temp;
			}
		}
	}
	return res;
}

int main(){
	for(int k=0;k<15;k++){
	vector<vector<string> > dp;   //dp[i][j]是将i个加号加到长度为j的字符串的位置的最小值 
	int m;  //m个加号 
	string s;   //s为输入的字符串 
	cin>>m;
	cin>>s;
	dp.resize(m+1);
	for(int i=0;i<m+1;i++){
		dp[i].resize(s.size()+1);
	}
	dp[0][0]="a";
	for(int i=1;i<s.size()+1;i++){
		dp[0][i]=s.substr(0,i);
	}
	for(int i=1;i<m+1;i++){
		for(int j=0;j<s.size()+1;j++){
			if(i>j-1) dp[i][j]="a";
			else{
				dp[i][j]=getdp(dp,i,j,s);
			}
		}
	} 
	if(dp[m][s.size()]=="a"){
		cout<<endl;  //按照题目的意思是输入的数字的个数和要添加的加号的个数可能是一样的,这种情况下就要什么都不输出 
	} else{
		cout<<dp[m][s.size()]<<endl;	
	}
	}
}

1.题目首先是要自己用字符串模拟加法,就会花费一定的时间

2.对这道题目的整体想法错了,想的是递归,但递归无疑是一种很暴力的方法,某人说的很对,刷题一个锻炼的是解决思路的能力,一个是写代码的能力,有了解决思路之后,再做代码实现

3.C++中s.substr(int a,int b)函数的使用方法是截取s中以位置a开始,长度为b的字符串,不是位置a和位置b之间的字符串,和其他语言中的不要搞混了,不要想当然

4.使用动态规划进行求解,dp[i][j]表示的是在长度为j的字符串中加入i个加号的和的最小值,永远都把加号加在最后一个字母后面。


马走日

总时间限制:

1000ms

内存限制:

1024kB

描述

马在中国象棋以日字形规则移动。

请编写一段程序,给定n*m大小的棋盘,以及马的初始位置(x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点。

输入

第一行为整数T(T < 10),表示测试数据组数。
每一组测试数据包含一行,为四个整数,分别为棋盘的大小以及初始位置坐标n,m,x,y。(0<=x<=n-1,0<=y<=m-1, m < 10, n < 10)

输出

每组测试数据包含一行,为一个整数,表示马能遍历棋盘的途径总数,0为无法遍历一次。

样例输入

1
5 4 0 0

样例输出

32
//马走日
//这道题目真的一点思路都没有
//智障吗 用递归啊
//!!!! 

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

//现在似乎是没有考虑无法被遍历的情况 

int cp=0;   //在外部定义全局变量 输出 返回 

int fx[8]={1,2,2,1,-1,-2,-2,-1},fy[8]={2,1,-1,-2,-2,-1,1,2};

bool canvisit(int x,int y,vector<vector<bool> >&visited){
	if(x<0||y<0||x>=visited.size()||y>=visited[0].size()) return false;   //越界 不可访问 
	if(visited[x][y]==true) return false;   //已被访问 不可再次被访问
	return true;
}


void visit(int i,int j,vector<vector<bool> >&visited,int cv){
		visited[i][j]=true;
		cv++;
		if(cv==visited.size()*visited[0].size()){
			cp++; 
			cv--;
			visited[i][j]=false;
			return;
		}
		else{
			if(canvisit(i-2,j-1,visited)) visit(i-2,j-1,visited,cv);
			if(canvisit(i-1,j-2,visited)) visit(i-1,j-2,visited,cv);
			if(canvisit(i-2,j+1,visited)) visit(i-2,j+1,visited,cv);
			if(canvisit(i-1,j+2,visited)) visit(i-1,j+2,visited,cv);
			if(canvisit(i+2,j-1,visited)) visit(i+2,j-1,visited,cv);
			if(canvisit(i+1,j-2,visited)) visit(i+1,j-2,visited,cv);
			if(canvisit(i+2,j+1,visited)) visit(i+2,j+1,visited,cv);
			if(canvisit(i+1,j+2,visited)) visit(i+1,j+2,visited,cv);
		}
		visited[i][j]=false;
		cv--;
}


int main(){
	int num;
	cin>>num;
	for(int k=0;k<num;k++){
		cp=0;
		int row,colum;
		cin>>row;
		cin>>colum;
		vector<vector<bool> >visited;
		visited.resize(row);
		for(int a=0;a<row;a++){
			visited[a].resize(colum);
		}
		int i,j;
		cin>>i;
		cin>>j;
		visit(i,j,visited,0);
		cout<<cp<<endl;
	}
	return 0;
} 

Word-Search Wonder

总时间限制:

1000ms

内存限制:

65536kB

描述

The Pyrates Restaurant was starting to fill up as Valentine McKee walked in. She scanned the crowd for her sister, brother-in-law, and nephew. Seeing her sister waving from the far end of the restaurant, she made her way back to their booth. ``Hi, Valentine,'' her sister and brother-in-law, Niki and Dennis Chapman, greeted her.
``Hi, guys,'' she replied. ``What are you doing, Wade?'' she asked her nephew. He was busy working on one of the restaurant's activity sheets with a crayon.

``I'm doing a word search game,'' Wade explained. ``I have to find all of these words in this big mess of letters. This is really hard.'' Wade looked intently at the paper in front of him.

``Can I help?'' asked Valentine, looking across the table at the activity sheet.

``Sure. These are the words we're looking for. They're the names of different kinds of Planes, Trains, and Automobiles.''

输入

The first line of input will specify the length (in characters) of the sides of the letter matrix (the matrix of letters will be square). The length, l, will be in the range 1 <= l <= 100. The next l lines of input will be the matrix itself, each line will contain l uppercase letters.

A list of words will follow. Each word will be on a line by itself; there will be 100 or fewer words. Each word will be 100 or fewer characters long, and will only contain uppercase letters.

The final line of input will contain a single zero character.

输出

Your program should attempt to find each word from the word list in the puzzle. A word is ``found'' if all the characters in the word can be traced in a single (unidirectional) horizontal, vertical, or diagonal line in the letter matrix. Words may not ``wrap around'' rows or columns, but horizontal and diagonal words may proceed from right to left (``backwards''). For each word that is found, your program should print the coordinates of its first and last letters in the matrix on a single line, separated by a single space. Coordinates are pairs of comma-separated integers (indexed from 1), where the first integer specifies the row number and the second integer specifies the column number.

If a word is not found, the string ``Not found'' should be output instead of a pair of coordinates.

Each word from the input can be ``found'' at most once in the puzzle.

样例输入

5
EDEEE
DISKE
ESEEE
ECEEE
EEEEE
DISC
DISK
DISP
0

样例输出

1,2 4,2
2,1 2,4
Not found
//word-search wonder
//自己的想法是直接循环判断,但这样存在要考虑倒着的情况
//看到的另一个解法是 直接考虑八个方向上的枚举
//真的是千万不要粗心啊,这得花多长时间debug啊 

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

void find(vector<vector<char> > letter,string s){
	int len=s.size();
	int add[8][2]={{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};
	for(int i=0;i<letter.size();i++){   //数组的每一个维度 
		for(int j=0;j<letter.size();j++){
			bool flag=false;
			for(int k=0;k<8;k++){  //对于每一个维度 
				for(int m=0;m<len;m++){   //对于此维度上的每一个字符 
					if(i+m*add[k][0]<0||i+m*add[k][0]>=letter.size()||j+m*add[k][1]<0||j+m*add[k][1]>=letter.size()||letter[i+m*add[k][0]][j+m*add[k][1]]!=s[m]){
						break;
					}else{
						if(m==len-1){
							flag=true;
							cout<<i+1<<","<<j+1<<" "<<i+m*add[k][0]+1<<","<<j+m*add[k][1]+1<<endl;
							return;
						}
					}
				} 
			}
		}
	}
	cout<<"Not found"<<endl;
	return;
}


int main(){
	int n;
	cin>>n;
	vector<vector<char> > letter;
	letter.resize(n);
	for(int i=0;i<n;i++){
		letter[i].resize(n);
	}
	for(int i=0;i<n;i++){
		string s;
		cin>>s;
		for(int j=0;j<n;j++){
			letter[i][j]=s[j];
		}
	}
	char ss[100];
	while(true){
//		cin>>s;
		scanf("%s",&ss);
		string s(ss);
		if(s=="0") break;
		find(letter,s);
	}
} 

写代码的时候一定要细心细心再细心,写完代码之后最后走查一遍,要不然之后debug的时候就会比较费时间。

在这种类似迷宫问题的问题中,如果需要向多个方向走,那么可以定义步长数组,对步长数组进行循环会比单独写每个方向简便一些。


A Mini Locomotive

总时间限制:

1000ms

内存限制:

65536kB

描述

A train has a locomotive that pulls the train with its many passenger coaches. If the locomotive breaks down, there is no way to pull the train. Therefore, the office of railroads decided to distribute three mini locomotives to each station. A mini locomotive can pull only a few passenger coaches. If a locomotive breaks down, three mini locomotives cannot pull all passenger coaches. So, the office of railroads made a decision as follows:

1. Set the number of maximum passenger coaches a mini locomotive can pull, and a mini locomotive will not pull over the number. The number is same for all three locomotives.
2. With three mini locomotives, let them transport the maximum number of passengers to destination. The office already knew the number of passengers in each passenger coach, and no passengers are allowed to move between coaches.
3. Each mini locomotive pulls consecutive passenger coaches. Right after the locomotive, passenger coaches have numbers starting from 1.

For example, assume there are 7 passenger coaches, and one mini locomotive can pull a maximum of 2 passenger coaches. The number of passengers in the passenger coaches, in order from 1 to 7, is 35, 40, 50, 10, 30, 45, and 60.

If three mini locomotives pull passenger coaches 1-2, 3-4, and 6-7, they can transport 240 passengers. In this example, three mini locomotives cannot transport more than 240 passengers.

Given the number of passenger coaches, the number of passengers in each passenger coach, and the maximum number of passenger coaches which can be pulled by a mini locomotive, write a program to find the maximum number of passengers which can be transported by the three mini locomotives.

输入

The first line of the input contains a single integer t (1 <= t <= 11), the number of test cases, followed by the input data for each test case. The input for each test case will be as follows:
The first line of the input file contains the number of passenger coaches, which will not exceed 50,000. The second line contains a list of space separated integers giving the number of passengers in each coach, such that the ith number of in this line is the number of passengers in coach i. No coach holds more than 100 passengers. The third line contains the maximum number of passenger coaches which can be pulled by a single mini locomotive. This number will not exceed 1/3 of the number of passenger coaches.

输出

There should be one line per test case, containing the maximum number of passengers which can be transported by the three mini locomotives.

样例输入

1
7
35 40 50 10 30 45 60
2

样例输出

240
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<string>
#define MP make_pair
#define SQ(x) ((x)*(x))
//思路:

//因为m<=N/3, 所以按照贪心的思想,为了拉更多的人,每个火车头一定是要拉m个连续的车厢。

//然后,为了求某段连续的车厢共有多少人,可以前缀和预处理, 某一段和=sum[ i ] - sum[ i-m].

//f[i][j] 代表前i个车厢,用j个火车头拉,最多能拉多少人。

//对于第i个车厢,如果当前这个车头选择要拉这个车厢,那么要把以i为最后一个车厢的连续m个车厢一起拉,所以状态转移方程是:

//f[i][j] = max(f[i-1][j], f[i-m][j-1]+sum[i]-sum[i-m]);


using namespace std;
typedef long long int64;

const double PI = acos(-1.0);  //截获PI的值!!! 
const int MAXN = 50010;
const int INF = 0x3f3f3f3f;
int n, m;
int w[MAXN], sum[MAXN];
int f[MAXN][4];


int main(){

    int nCase;              // 案例个数 
    scanf("%d", &nCase);
    while(nCase--){
        scanf("%d", &n);            // 火车有几节 

        for(int i=1; i<=n; ++i){
            scanf("%d", &w[i]);           // w[i]用来存每节火车里面有的人数 
            sum[i] = sum[i-1] + w[i];        // 前i节车厢里面一共有多少人 
        }

        scanf("%d", &m);       //  最多可以推动几节火车 

        memset(f, 0, sizeof(f));
        
        for(int i=m; i<=n; ++i){
            for(int j=3; j>=1; --j){
                f[i][j] = max(f[i-1][j], f[i-m][j-1]+sum[i]-sum[i-m]);   f[i][j] 代表前i个车厢,用j个火车头拉,最多能拉多少人。
                              // 不要第i个车厢    // 前i-m个车厢用j-1个车头来拉+后m个车厢有的人数 
            }
        }
          
        printf("%d\n", f[n][3]);
    }
    return 0;
}

这道题目真的使花了很久去写了,就是一个01背包问题

1.关键的一点是要考虑到贪心,为了最终拉的乘客最多,那么每个车头都要拉上最多的车厢。如果没考虑到贪心,就会复杂很多了。

2.动态规划算法中存的大多是截至到这里的最大值,想清楚再写吧

这个问题是针对于01背包的问题,注意和求图中一个点到另一个点的最小距离做区分。真的,想清楚再写。

3.在程序编写的过程中会出现触碰到边界的情况,可以在最外层再加一层0,这样处理起来也简单一些。


Game Prediction

总时间限制:

1000ms

内存限制:

65536kB

描述

Suppose there are M people, including you, playing a special card game. At the beginning, each player receives N cards. The pip of a card is a positive integer which is at most N*M. And there are no two cards with the same pip. During a round, each player chooses one card to compare with others. The player whose card with the biggest pip wins the round, and then the next round begins. After N rounds, when all the cards of each player have been chosen, the player who has won the most rounds is the winner of the game.



Given your cards received at the beginning, write a program to tell the maximal number of rounds that you may at least win during the whole game.

输入

The input consists of several test cases. The first line of each case contains two integers m (2 <= m <= 20) and n (1<= n <= 50), representing the number of players and the number of cards each player receives at the beginning of the game, respectively. This followed by a line with n positive integers, representing the pips of cards you received at the beginning. Then a blank line follows to separate the cases.

The input is terminated by a line with two zeros.

输出

For each test case, output a line consisting of the test case number followed by the number of rounds you will at least win during the game.

样例输入

2 5
1 7 2 10 9

6 11
62 63 54 66 65 61 57 56 50 53 48

0 0

样例输出

Case 1: 2
Case 2: 4
//游戏预测
#include<iostream>
#include<stdio.h>
#include<vector> 

using namespace std;

int main(){
	int m,n;
	int count=1;
	while(true){
		cin>>m;
		cin>>n;
		if(m==0&&n==0) break;
		vector<bool> have(m*n+1,false);
		int temp;
		for(int i=0;i<n;i++){
			cin>>temp;
			have[temp]=true;
		}
		int succ=0;
		int fail=0;
		for(int i=m*n;i>0;i--){
			if(have[i]==true&&fail==0){
				succ++;
			}else if(have[i]==false){
				fail++;
			}else if(have[i]==true&&fail!=0){
				fail--;
			}
		}
		cout<<"Case "<<count<<": "<<succ<<endl;
		count++;
	}
	return 0;
} 

1.主要还是贪心的思想

因为是要找出肯定能赢的次数,所以考虑最坏的情况,自己这里尽最大的努力。自己出牌永远都要出最大的,只有有比当前这张牌大的在别人手上,那么就认为这一轮一定会输,但是这一轮输掉的时候也会将别人的一张(不要考虑那么复杂,和多少人没有关系,万一所有的大牌都在别人那里呢)比自己大的牌消耗掉。

2.想清楚再写,坚持住哦,加油哦


计算两个日期之间的天数

总时间限制:

1000ms

内存限制:

65536kB

描述

给定两个日期,计算相差的天数。比如2010-1-1和2010-1-3相差2天。
 

输入

共两行:
第一行包含三个整数startYear,startMonth,startDay,分别是起始年、月、日。
第二行包含三个整数endYear,endMonth,endDay,分别是结束年、月、日。
相邻两个整数之间用单个空格隔开。

年份范围在1~3000。保证日期正确且结束日期不早于起始日期。

输出

输出一个整数,即是两个日期相差的天数。

样例输入

2008 1 1
2009 1 1

样例输出

366

 

 

提示

闰年被定义为能被4整除的年份,但是能被100整除而不能被400整除的年是例外,它们不是闰年。闰年的2月份有29天。

//计算两个日期之间的天数
#include<iostream>
using namespace std;

bool isrun(int y){
	if(y%4!=0){
		return false;
	}
	if(y%100==0&&y%400!=0){
		return false;
	}
	return true;
}

int getDays(int y,int m,int d){  //计算从当前日期到0001年1月1日有多少天 
	int days[12]={31,30,31,28,31,30,31,31,30,31,30,31};
	int res=0;
	for(int i=1;i<y;i++){
		if(isrun(i)){
			res+=366;
		}
		else{
			res+=365;
		}
	}
	for(int i=1;i<m;i++){
		if(i==2){
			if(isrun(y)) res+=29;
			else res+=28;
		}
		else{
			res+=days[i-1];
		}
	}
	res+=d;
	return res;
} 

int main(){
	int y1,m1,d1;
	int y2,m2,d2;
	cin>>y1;
	cin>>m1;
	cin>>d1;
	cin>>y2;
	cin>>m2;
	cin>>d2;
	cout<<getDays(y2,m2,d2)-getDays(y1,m2,d1);
	return 0;
}

是夏令营的第一道题目,算是比较简单的,但不可否认如果直接算两个日期之间差的天数的话会是比较复杂的,有些乱的。

所以选择了分别计算两者到1年1月1日的时间,只需要做减法即可,(这么做对于靠后的时间复杂度是有些高的,不知道会不会超时,在平台式没有找到原题。

另一种方法是直接获取这一天的时间戳(调用Java中的库),相减然后除以一天的秒数。


回文子串

总时间限制:

1000ms

内存限制:

65536kB

描述

给定一个字符串,寻找并输出字符串中最长回文子串。回文串即从左到右和从右到左读都一样的字符串。
如果字符串中包含多个回文子串,则返回第一个。

输入

第一行是整数n,字符串的个数(n < 20)

输出

接下来n行,每行一个字符串
字符串的长度不超过100

样例输入

3
ab
babadec
scdedcd

样例输出

a
bab
cdedc
//最长回文子串

#include<iostream>
using namespace std;

bool ishuiwen(string a){
	int begin=0;
	int end=a.size()-1;
	while(begin<=end){
		if(a[begin]!=a[end]) return false;
		else{
			begin++;
			end--;
		}
	}
}

int main(){
	int num;
	cin>>num;
	for(int i=0;i<num;){
		string s;
		cin>>s;
		for(int k=s.size();k>0;k--){
			for(int j=0;j<s.size();j++){
				if(j+k<=s.size()){
					if(ishuiwen(s.substr(j,k))){
						cout<<s.substr(j,k)<<endl;
						goto a;
					}
				}else{
					continue;
				}
			}
		}
		a:i++; 
	}
	return 0;
}

从长到短遍历即可,没有这个的原题,不知道会不会超时orz

另外的两种方法

1.从中间向两边扩散

2.一种类似KMP算法那种形式的方法(学不会)


Euro Efficiency

总时间限制:

1000ms

内存限制:

65536kB

描述

On January 1st 2002, The Netherlands, and several other European countries abandoned their national currency in favour of the Euro. This changed the ease of paying, and not just internationally.
A student buying a 68 guilder book before January 1st could pay for the book with one 50 guilder banknote and two 10 guilder banknotes, receiving two guilders in change. In short:50+10+10-1-1=68. Other ways of paying were: 50+25-5-1-1, or 100-25-5-1-1.Either way, there are always 5 units (banknotes or coins) involved in the payment process, and it
could not be done with less than 5 units.
Buying a 68 Euro book is easier these days: 50+20-2 = 68, so only 3 units are involved.This is no coincidence; in many other cases paying with euros is more efficient than paying with guilders. On average the Euro is more efficient. This has nothing to do, of course, with the value of the Euro, but with the units chosen. The units for guilders used to be: 1, 2.5, 5, 10, 25, 50,whereas the units for the Euro are: 1, 2, 5, 10, 20, 50.
For this problem we restrict ourselves to amounts up to 100 cents. The Euro has coins with values 1, 2, 5, 10, 20, 50 eurocents. In paying an arbitrary amount in the range [1, 100] eurocents, on average 2.96 coins are involved, either as payment or as change. The Euro series is not optimal in this sense. With coins 1, 24, 34, 39, 46, 50 an amount of 68 cents can be paid using two coins.The average number of coins involved in paying an amount in the range [1, 100] is 2.52.
Calculations with the latter series are more complex, however. That is, mental calculations.These calculations could easily be programmed in any mobile phone, which nearly everybody carries around nowadays. Preparing for the future, a committee of the European Central Bank is studying the efficiency of series of coins, to find the most efficient series for amounts up to 100 eurocents. They need your help.
Write a program that, given a series of coins, calculates the average and maximum number of coins needed to pay any amount up to and including 100 cents. You may assume that both parties involved have sufficient numbers of any coin at their disposal.

输入

The first line of the input contains the number of test cases. Each test case is described by 6 different positive integers on a single line: the values of the coins, in ascending order. The first number is always 1. The last number is less than 100.

输出

For each test case the output is a single line containing first the average and then the maximum number of coins involved in paying an amount in the range [1, 100]. These values are separated by a space. As in the example, the average should always contain two digits behind the decimal point. The maximum is always an integer.

样例输入

3
1 2 5 10 20 50
1 24 34 39 46 50
1 2 3 7 19 72

样例输出

2.96 5
2.52 3
2.80 4
//支付所需的最小硬币数
///完全背包? 
//可以加可以减 最少用多少表示出来

//用动态规划的方式 加一遍 减一遍

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

int main(){
	int num;
	cin>>num;
	int val[7];
	int dp[3010];
	while(num--){
		for(int i=1;i<=6;i++){
			cin>>val[i];
		}
		for(int i=0;i<=3000;i++){
			dp[i]=10000000;
		}
		dp[0]=0;
		for(int i=1;i<=6;i++){
			for(int j=val[i];j<=3000;j++){
				dp[j]=dp[j]<dp[j-val[i]]+1?dp[j]:dp[j-val[i]]+1;
			}
		}
		
		for(int i=1;i<=6;i++){
			for(int j=3000-val[i];j>=1;j--){
				dp[j]=min(dp[j],dp[j+val[i]]+1);
			}
		}

		int sum=0;
		int maxn=0;
		for(int i=1;i<=100;i++){
			sum+=dp[i];
			maxn=max(maxn,dp[i]);
		}
//		cout<<(sum+0.0)/100.0<<" "<<maxn<<endl;
		printf("%.2f %d\n",(sum+0.0)/100.0,maxn);
	}
	return 0;
} 

完全背包问题,由于需要有负数,所以需要从前往后,以及从后往前分别遍历一遍,求dp序列,由于给钱的上界并不在100,所以要高一点,然后是要2000才可以?


The Die Is Cast

总时间限制:

1000ms

内存限制:

65536kB

描述

InterGames is a high-tech startup company that specializes in developing technology that allows users to play games over the Internet. A market analysis has alerted them to the fact that games of chance are pretty popular among their potential customers. Be it Monopoly, ludo or backgammon, most of these games involve throwing dice at some stage of the game.
Of course, it would be unreasonable if players were allowed to throw their dice and then enter the result into the computer, since cheating would be way to easy. So, instead, InterGames has decided to supply their users with a camera that takes a picture of the thrown dice, analyzes the picture and then transmits the outcome of the throw automatically.

For this they desperately need a program that, given an image containing several dice, determines the numbers of dots on the dice.

We make the following assumptions about the input images. The images contain only three different pixel values: for the background, the dice and the dots on the dice. We consider two pixels connected if they share an edge - meeting at a corner is not enough. In the figure, pixels A and B are connected, but B and C are not.


A set S of pixels is connected if for every pair (a,b) of pixels in S, there is a sequence a1, a2, ..., ak in S such that a = a1 and b = ak , and ai and ai+1 are connected for 1 <= i < k.

We consider all maximally connected sets consisting solely of non-background pixels to be dice. `Maximally connected' means that you cannot add any other non-background pixels to the set without making it dis-connected. Likewise we consider every maximal connected set of dot pixels to form a dot.

输入

The input consists of pictures of several dice throws. Each picture description starts with a line containing two numbers w and h, the width and height of the picture, respectively. These values satisfy 5 <= w, h <= 50.

The following h lines contain w characters each. The characters can be: "." for a background pixel, "*" for a pixel of a die, and "X" for a pixel of a die's dot.

Dice may have different sizes and not be entirely square due to optical distortion. The picture will contain at least one die, and the numbers of dots per die is between 1 and 6, inclusive.

The input is terminated by a picture starting with w = h = 0, which should not be processed.

输出

For each throw of dice, first output its number. Then output the number of dots on the dice in the picture, sorted in increasing order.

Print a blank line after each test case.

样例输入

30 15
..............................
..............................
...............*..............
...*****......****............
...*X***.....**X***...........
...*****....***X**............
...***X*.....****.............
...*****.......*..............
..............................
........***........******.....
.......**X****.....*X**X*.....
......*******......******.....
.....****X**.......*X**X*.....
........***........******.....
..............................
0 0

样例输出

Throw 1
1 2 2 4

来源

Southwestern European Regional Contest 1998

//观察色子点数

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

int t=0;
int num[1000];
int path[2][4]={{0,1,0,-1},{-1,0,1,0}};
int n,m;

void dfs2(vector<vector<char> > &game,int x,int y){    //遍历X 
	game[x][y]='*';
	int xx,yy;
	for(int i=0;i<4;i++){
		xx=x+path[0][i];
		yy=y+path[1][i];
		if(xx<0||yy<0||xx>=m||yy>=n||game[xx][yy]=='*') continue;
		if(game[xx][yy]=='X'){
			dfs2(game,xx,yy);
		}
	}
}

void dfs(vector<vector<char> > &game,int x,int y){  //遍历* 
	int xx,yy;
	game[x][y]='.';
	for(int i=0;i<4;i++){
		xx=x+path[0][i];
		yy=y+path[1][i];
		if(xx<0||yy<0||xx>=m||yy>=n||game[xx][yy]=='.') continue;
		if(game[xx][yy]=='X'){
			dfs2(game,xx,yy);
			num[t]++;
		}
		///因为在上面的部分是继续dfs了的,在此之后将原来的点设置\
		为了“*”,还需要继续遍历,并且这里不能用elseif,之前的对之后的会有影响 
		if(game[xx][yy]=='*'){
			dfs(game,xx,yy);
		}
//		else if(game[xx][yy]=='X'){
//			dfs2(game,xx,yy);
//			num[t]++;
//		}
	}
} 

int cmp (const void *a,const void *b)

{

    return *(int *)a-*(int *)b;

}

int main(){
	int k=0;
	while(true){
		for(int i=0;i<1000;i++){
			num[i]=0;
		}
		t=0;
		cin>>n;  //n列 
		cin>>m;  //m行 
		if(m==0&&n==0) break;
		vector<vector<char> > game;
		game.resize(m);
		for(int i=0;i<m;i++){
			game[i].resize(n);
			for(int j=0;j<n;j++){
				game[i][j]='.';
			}
		}
		for(int i=0;i<m;i++){
			for(int j=0;j<n;j++){
				cin>>game[i][j];
			}
		}
			
		for(int i=0;i<m;i++){
			for(int j=0;j<n;j++){
				//cout<<"i,j:"<<i<<" "<<j<<endl;
				if(game[i][j]=='*'){
					dfs(game,i,j);
					t++;
				}
			}
		}
//		sort(num,num+1000);
//		cout<<"Throw "<<k++<<endl;
//		int i;
//		if(t==0){
//			cout<<0; 
//		}
//		else if(t==1){
//			cout<<num[999];
//		}
//		else{
//			for(i=t;i>1;i--){
//				cout<<num[1000-i]<<" ";
//			}
//			cout<<num[999];
//		}
		        /**排序输出**/

        qsort(num,t,sizeof (num[0]),cmp);

        printf("Throw %d\n",++k);
        int i;
        for(i=0; i<t-1; i++)

            printf("%d ",num[i]);

        printf("%d\n",num[i]);

        printf("\n");
		 
	}
}

首先由于这个题不是自己直接想出来写的,所以就导致很懵,还是要想清楚啊。

题目的意思是要找*中包围着的X,采用2层的深度优先搜索,在第一层中找"*",找到"*"之后再继续去找"X",另外还有比较重要的是在处理完这个位置之后需要将这个位置变成"."或"*",以防这个点被多次处理,无法跳出。

还是要想清楚啊!!!


食物链

总时间限制:

1000ms

内存限制:

65536kB

描述

动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。
现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。
有人用两种说法对这N个动物所构成的食物链关系进行描述:
第一种说法是"1 X Y",表示X和Y是同类。
第二种说法是"2 X Y",表示X吃Y。
此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
1) 当前的话与前面的某些真的话冲突,就是假话;
2) 当前的话中X或Y比N大,就是假话;
3) 当前的话表示X吃X,就是假话。
你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。

输入

第一行是两个整数N和K,以一个空格分隔。
以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。
若D=1,则表示X和Y是同类。
若D=2,则表示X吃Y。

输出

只有一个整数,表示假话的数目。

样例输入

100 7
1 101 1 
2 1 2
2 2 3 
2 3 3 
1 1 3 
2 3 1 
1 5 5

样例输出

3

来源

#################

确认过眼神,是我不会的题,用暴力的解法的话估计是会超时的。

看题目的解析,是需要采用并查集的方式,建立不同对象之间的关系,然后再判断当前这句话与已有的关系是否符合。

并查集似乎是要建立那种一层一层的关系,但是直接用简单的数据结构又不太好处理,所以需要追根溯源。

多用在人际关系网中~


判决素数个数

总时间限制:

1000ms

内存限制:

65536kB

描述

输入两个整数X和Y,输出两者之间的素数个数(包括X和Y)。

输入

两个整数X和Y(1 <= X,Y <= 105)。

输出

输出一个整数,表示X,Y之间的素数个数(包括X和Y)。

样例输入

1 100

样例输出

25
//素数筛法
#include<iostream>
#include<vector>
#include<stdio.h> 
#include<stdlib.h>
#include<cstdio>
#include<string.h>
using namespace std;

bool isprime[100005];
int array[100000];

int main(){
	int begin;
	int end;
	int cnt=0;
	cin>>begin;
	cin>>end;
	if(begin>end){
		swap(begin,end);
	}
	if(begin==1){
		begin=2;
	}
	memset(isprime,true,sizeof(isprime));  //全部初始化为true,一个一个往掉筛
	isprime[1]=false;
	for(int i=2;i<=100000;i++){
		if(isprime[i]){   //从2开始,依次往掉筛 
			array[cnt++]=i;
			for(int j=i*2;j<=100000;j+=i){
				isprime[j]=false;
			}
		}
	}
	int sum=0;
	for(int i=0;i<cnt;i++){
		if(array[i]>end) break;
		else if(array[i]>=begin) sum++;
	} 
	printf("%d\n",sum);
	return 0;
} 

很遗憾自己之前查素数一直是从1到根号n查,无疑是错误的,在这种情况下会超时

需要注意的几点有

1.1不是素数,素数是除1以外的只能被1和它本身整除的自然数

2.素数筛法:从2开始,将它的倍数全部删除掉,依次循环之后的其他数,直到筛子为空?

使用一个数组标记这个数是否被筛掉,另一个数组存放是素数的值,其实也可以不到100000,到输入的边界即可。


编码字符串

描述

在数据压缩中,一个常用的方法是行程长度编码压缩。对于一个待压缩的字符串,我们可以依次记录每个字符及重复的次数。例如,待压缩的字符串为"aaabbbbcbb",压缩结果为(a,3)(b,4)(c,1)(b,2)。这种压缩对于相邻数据重复较多的情况有效,如果重复状况较少,则压缩的效率较低。

现要求根据输入的字符串,首先将字符串中所有大写字母转化为小写字母,然后将字符串进行压缩。

输入

一个字符串,长度大于0,且不超过1000,全部由大写或小写字母组成。

输出

输出为编码之后的字符串,形式为:(a,3)(b,4)(c,1)(d,2),即每对括号内分别为小写字符及重复的次数,不含任何空格。

样例输入

aAABBbBCCCaaaaa

样例输出

(a,3)(b,4)(c,3)(a,5)

来源

cs10116 final exam

//编码字符串
#include<iostream>
#include<vector>
using namespace std;

int main(){
	string s;
	cin>>s;
	string res;
	if(s[0]>='A'&&s[0]<='Z'){
			s[0]=s[0]-'A'+'a';
	}
	char first=s[0];
	int cnt=1;
	for(int i=1;i<s.size();i++){
		if(s[i]>='A'&&s[i]<='Z'){
			s[i]=s[i]-'A'+'a';
		}
		if(s[i]==first){
			cnt++;
		}else{
			res.push_back('(');
			res.push_back(first);
			res.push_back(',');
			char temp=cnt+'0';
			res.push_back(temp);
			res.push_back(')'); 
			first=s[i];
			cnt=1;
		}
	}
	res.push_back('(');
	res.push_back(first);
	res.push_back(',');
	char temp=cnt+'0';
	res.push_back(temp);
	res.push_back(')');
	cout<<res;
	return 0;
} 

岛屿周长

总时间限制:

1000ms

内存限制:

65536kB

描述

用一个n*m的二维数组表示地图,1表示陆地,0代表海水,每一格都表示一个1*1的区域。地图中的格子只能横向或者纵向连接(不能对角连接),连接在一起的陆地称作岛屿,同时整个地图都被海水围绕。假设给出的地图中只会有一个岛屿,并且岛屿中不会有湖(即不会有水被陆地包围的情况出现)。请判断所给定的二维地图中岛屿的周长。

输入

第一行为n和m,表示地图的大小(1<=n<=100, 1<=m<=100)。接下来n行,每行有m个数,分别描述每一格的数值。数值之间均用空格隔开。

输出

只有一行,即岛屿的周长(正整数)。

样例输入

3 4
1 1 1 0
0 1 0 0
1 1 0 0

样例输出

14

来源

cs10116 final exam

//岛屿周长
#include<iostream>
#include<vector>
using namespace std;

bool isisland(vector<vector<int> >island,int x,int y){
	if(x<0||x>=island.size()||y<0||y>=island[0].size()){
		return false;
	}
	else if(island[x][y]==1) {
		//cout<<x<<" "<<y<<endl;
		return true;
	}
	else return false;
}

int main(){
	int n;
	int m;
	cin>>n;
	cin>>m;
	vector<vector<int> > island;
	island.resize(n);
	for(int i=0;i<n;i++){
		island[i].resize(m);
	}
	
	int cnt=0;
	int temp;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>island[i][j];
			if(island[i][j]==1) cnt++;
		}
	}
	
	cnt=cnt*4;
	
	int path[2][4]={{0,1,0,-1},{1,0,-1,0}}; 
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			//cout<<i<<" "<<j<<" -------------------------"<<endl;
			if(island[i][j]==1){
				for(int k=0;k<4;k++){
					int ii=i+path[0][k];
					int jj=j+path[1][k];
					if(isisland(island,ii,jj)) cnt--;
				}
			}
		}
	}
	cout<<cnt;
	return 0;
} 

求岛屿的周长,真的,一看到这样的题差一点就去用DFS求了。

先看一共有多少个岛屿,先认为岛屿有4条边,然后依次遍历每个岛屿,如果这个岛屿与其他岛屿相邻,那么就减去一条边。


怪盗基德的滑翔翼

总时间限制:

1000ms

内存限制:

65536kB

描述

 

怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯。而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。

有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出的足球破坏了。不得已,怪盗基德只能操作受损的滑翔翼逃脱。

假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同。初始时,怪盗基德可以在任何一幢建筑的顶端。他可以选择一个方向逃跑,但是不能中途改变方向(因为中森警部会在后面追击)。因为滑翔翼动力装置受损,他只能往下滑行(即:只能从较高的建筑滑翔到较低的建筑)。他希望尽可能多地经过不同建筑的顶部,这样可以减缓下降时的冲击力,减少受伤的可能性。请问,他最多可以经过多少幢不同建筑的顶部(包含初始时的建筑)?

 

输入

输入数据第一行是一个整数K(K < 100),代表有K组测试数据。
每组测试数据包含两行:第一行是一个整数N(N < 100),代表有N幢建筑。第二行包含N个不同的整数,每一个对应一幢建筑的高度h(0 < h < 10000),按照建筑的排列顺序给出。

输出

对于每一组测试数据,输出一行,包含一个整数,代表怪盗基德最多可以经过的建筑数量。

样例输入

3
8
300 207 155 299 298 170 158 65
8
65 158 170 298 299 155 207 300
10
2 1 3 4 5 6 7 8 9 10

样例输出

6
6
9

####思路为动态规划

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值