北京大学计算机系2009应试硕士生上机考试(D-F)
D:
代码
/**********************************************************************************
2560 - Freckles
Time Limit:
1000ms
Memory limit:
65536kB
题目描述
In an episode of the Dick Van Dyke show, little Richie connects the freckles on his Dad's back to form a picture of the Liberty Bell. Alas, one of the freckles turns out to be a scar, so his Ripley's engagement falls through.
Consider Dick's back to be a plane with freckles at various (x,y) locations. Your job is to tell Richie how to connect the dots so as to minimize the amount of ink used. Richie connects the dots by drawing straight lines between pairs, possibly lifting the pen between lines. When Richie is done there must be a sequence of connected lines from any freckle to any other freckle.
输入
The first line contains 0 < n <= 100, the number of freckles on Dick's back. For each freckle, a line follows; each following line contains two real numbers indicating the (x,y) coordinates of the freckle.
输出
Your program prints a single real number to two decimal places: the minimum total length of ink lines that can connect all the freckles.
样例输入
3
1.0 1.0
2.0 2.0
2.0 4.0
样例输出
3.41
**********************************************************************************/
/**********************************************************************************
解题思路:
一个完全图,求最小生成树的路径之和.
先构造一个完全图,一共99+98+...+1 = 4950条边。按照边来存在一个数组中。
然后利用Kruskal算法,先按照边的从小到大对图快速排序。
然后构造一个并查集的数据结构(利用一个set数组和一个映射标记数组),从小到大遍历图中的边,
如果边的两个顶点mapping映射的并查集是同一个并查集,那么就表示这两个点式连同的,
否则就将这两个点映射的并查集合并。然后算上这条边的长度。
**********************************************************************************/
#include <iostream>
#include <cmath>
#include <cctype>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <list>
//#include <stdlib.h>
//#include <iomanip>
using namespace std;
struct edge
{
int p1, p2;
double distance;
};
double points[100][2];
//用边表示的图
edge graph[4951];
int compare(const void *a, const void *b)
{
double temp;
edge *pa = (edge*)a;
edge *pb = (edge*)b;
temp = (pa->distance) - (pb->distance);
if (temp < 0)
return -1;
else if (temp > 0)
return 1;
else
return 0;
}
int main()
{
int n, count = 0;
double t1, t2, answer = 0.0;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> points[i][0] >> points[i][1];
}
//构造图
for (int i = 0; i < n; i++)
{
for (int j = i+1; j < n; j++)
{
graph[count].p1 = i;
graph[count].p2 = j;
t1 = fabs(points[i][0] - points[j][0]);
t2 = fabs(points[i][1] - points[j][1]);
graph[count].distance = sqrt(t1*t1 + t2*t2);
count++;
}
}
//快速排序
qsort(graph, count, sizeof(edge), compare);
//模拟一个并查集
set<int> si[100];
//mapping用来对应点和所在的集合
//例如:mapping[3] = 6表示3归并在si[6]中
int mapping[100], map1, map2;
for (int i = 0; i < n; i++)
{
si[i].insert(i);
mapping[i] = i;
}
//kruskal算法
for (int i = 0; i < count; i++)
{
map1 = mapping[graph[i].p1];
map2 = mapping[graph[i].p2];
//对应的两个点已经合并了
if (map1 == map2)
continue;
//否则将两个点所在的代表集合合并
else
{
si[map1].insert(si[map2].begin(), si[map2].end());
for (set<int>::iterator iter = si[map1].begin(); iter != si[map1].end(); iter++)
{
mapping[*iter] = map1;
}
answer += graph[i].distance;
}
}
printf("%.2f\n", answer);
return 0;
}
2560 - Freckles
Time Limit:
1000ms
Memory limit:
65536kB
题目描述
In an episode of the Dick Van Dyke show, little Richie connects the freckles on his Dad's back to form a picture of the Liberty Bell. Alas, one of the freckles turns out to be a scar, so his Ripley's engagement falls through.
Consider Dick's back to be a plane with freckles at various (x,y) locations. Your job is to tell Richie how to connect the dots so as to minimize the amount of ink used. Richie connects the dots by drawing straight lines between pairs, possibly lifting the pen between lines. When Richie is done there must be a sequence of connected lines from any freckle to any other freckle.
输入
The first line contains 0 < n <= 100, the number of freckles on Dick's back. For each freckle, a line follows; each following line contains two real numbers indicating the (x,y) coordinates of the freckle.
输出
Your program prints a single real number to two decimal places: the minimum total length of ink lines that can connect all the freckles.
样例输入
3
1.0 1.0
2.0 2.0
2.0 4.0
样例输出
3.41
**********************************************************************************/
/**********************************************************************************
解题思路:
一个完全图,求最小生成树的路径之和.
先构造一个完全图,一共99+98+...+1 = 4950条边。按照边来存在一个数组中。
然后利用Kruskal算法,先按照边的从小到大对图快速排序。
然后构造一个并查集的数据结构(利用一个set数组和一个映射标记数组),从小到大遍历图中的边,
如果边的两个顶点mapping映射的并查集是同一个并查集,那么就表示这两个点式连同的,
否则就将这两个点映射的并查集合并。然后算上这条边的长度。
**********************************************************************************/
#include <iostream>
#include <cmath>
#include <cctype>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <list>
//#include <stdlib.h>
//#include <iomanip>
using namespace std;
struct edge
{
int p1, p2;
double distance;
};
double points[100][2];
//用边表示的图
edge graph[4951];
int compare(const void *a, const void *b)
{
double temp;
edge *pa = (edge*)a;
edge *pb = (edge*)b;
temp = (pa->distance) - (pb->distance);
if (temp < 0)
return -1;
else if (temp > 0)
return 1;
else
return 0;
}
int main()
{
int n, count = 0;
double t1, t2, answer = 0.0;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> points[i][0] >> points[i][1];
}
//构造图
for (int i = 0; i < n; i++)
{
for (int j = i+1; j < n; j++)
{
graph[count].p1 = i;
graph[count].p2 = j;
t1 = fabs(points[i][0] - points[j][0]);
t2 = fabs(points[i][1] - points[j][1]);
graph[count].distance = sqrt(t1*t1 + t2*t2);
count++;
}
}
//快速排序
qsort(graph, count, sizeof(edge), compare);
//模拟一个并查集
set<int> si[100];
//mapping用来对应点和所在的集合
//例如:mapping[3] = 6表示3归并在si[6]中
int mapping[100], map1, map2;
for (int i = 0; i < n; i++)
{
si[i].insert(i);
mapping[i] = i;
}
//kruskal算法
for (int i = 0; i < count; i++)
{
map1 = mapping[graph[i].p1];
map2 = mapping[graph[i].p2];
//对应的两个点已经合并了
if (map1 == map2)
continue;
//否则将两个点所在的代表集合合并
else
{
si[map1].insert(si[map2].begin(), si[map2].end());
for (set<int>::iterator iter = si[map1].begin(); iter != si[map1].end(); iter++)
{
mapping[*iter] = map1;
}
answer += graph[i].distance;
}
}
printf("%.2f\n", answer);
return 0;
}
E:
代码
/**********************************************************************************
1666 - Candy Sharing Game
Time Limit:
1000ms
Memory limit:
10000kB
题目描述
A number of students sit in a circle facing their teacher in the center. Each student initially has an even number of pieces of candy. When the teacher blows a whistle, each student simultaneously gives half of his or her candy to the neighbor on the right. Any student, who ends up with an odd number of pieces of candy, is given another piece by the teacher. The game ends when all students have the same number of pieces of candy.
Write a program which determines the number of times the teacher blows the whistle and the final number of pieces of candy for each student from the amount of candy each child starts with.
输入
The input may describe more than one game. For each game, the input begins with the number N of students,followed by N (even) candy counts for the children counter-clockwise around the circle. The input ends with a student count of 0. Each input number is on a line by itself.
输出
For each game, output the number of rounds of the game followed by the amount of candy each child ends up with,both on one line.
样例输入
6
36
2
2
2
2
2
11
22
20
18
16
14
12
10
8
6
4
2
4
2
4
6
8
0
样例输出
15 14
17 22
4 8
提示
Notes:
The game ends in a finite number of steps because:
1. The maximum candy count can never increase.
2. The minimum candy count can never decrease.
3. No one with more than the minimum amount will ever decrease to the minimum.
4. If the maximum and minimum candy count are not the same, at least one student with the minimum amount must have their count increase
**********************************************************************************/
/**********************************************************************************
解题思路:
模拟题。
**********************************************************************************/
#include <iostream>
#include <cmath>
#include <cctype>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <list>
//#include <stdlib.h>
//#include <iomanip>
using namespace std;
int main()
{
int n, *stu, count, temp;
bool isEqual;
cin >> n;
while (n != 0)
{
count = 0;
isEqual = false;
stu = new int[n];
for (int i = 0; i < n; i++)
{
cin >> stu[i];
}
while (!isEqual)
{
isEqual = true;
for (int i = 0; i < n; i++)
{
stu[i] /= 2;
}
temp = stu[n-1];
for (int i = n-2; i >= 0; i--)
stu[i+1] += stu[i];
stu[0] += temp;
for(int i = 0; i < n; i++)
{
if (stu[i] % 2 != 0)
stu[i]++;
}
count++;
for (int i = 0; i < n-1; i++)
{
if(stu[i] != stu[i+1])
isEqual = false;
}
}
cout << count << " " << stu[0] << endl;
delete[] stu;
cin >> n;
}
return 0;
}
1666 - Candy Sharing Game
Time Limit:
1000ms
Memory limit:
10000kB
题目描述
A number of students sit in a circle facing their teacher in the center. Each student initially has an even number of pieces of candy. When the teacher blows a whistle, each student simultaneously gives half of his or her candy to the neighbor on the right. Any student, who ends up with an odd number of pieces of candy, is given another piece by the teacher. The game ends when all students have the same number of pieces of candy.
Write a program which determines the number of times the teacher blows the whistle and the final number of pieces of candy for each student from the amount of candy each child starts with.
输入
The input may describe more than one game. For each game, the input begins with the number N of students,followed by N (even) candy counts for the children counter-clockwise around the circle. The input ends with a student count of 0. Each input number is on a line by itself.
输出
For each game, output the number of rounds of the game followed by the amount of candy each child ends up with,both on one line.
样例输入
6
36
2
2
2
2
2
11
22
20
18
16
14
12
10
8
6
4
2
4
2
4
6
8
0
样例输出
15 14
17 22
4 8
提示
Notes:
The game ends in a finite number of steps because:
1. The maximum candy count can never increase.
2. The minimum candy count can never decrease.
3. No one with more than the minimum amount will ever decrease to the minimum.
4. If the maximum and minimum candy count are not the same, at least one student with the minimum amount must have their count increase
**********************************************************************************/
/**********************************************************************************
解题思路:
模拟题。
**********************************************************************************/
#include <iostream>
#include <cmath>
#include <cctype>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <list>
//#include <stdlib.h>
//#include <iomanip>
using namespace std;
int main()
{
int n, *stu, count, temp;
bool isEqual;
cin >> n;
while (n != 0)
{
count = 0;
isEqual = false;
stu = new int[n];
for (int i = 0; i < n; i++)
{
cin >> stu[i];
}
while (!isEqual)
{
isEqual = true;
for (int i = 0; i < n; i++)
{
stu[i] /= 2;
}
temp = stu[n-1];
for (int i = n-2; i >= 0; i--)
stu[i+1] += stu[i];
stu[0] += temp;
for(int i = 0; i < n; i++)
{
if (stu[i] % 2 != 0)
stu[i]++;
}
count++;
for (int i = 0; i < n-1; i++)
{
if(stu[i] != stu[i+1])
isEqual = false;
}
}
cout << count << " " << stu[0] << endl;
delete[] stu;
cin >> n;
}
return 0;
}
F:
代码
/**********************************************************************************
2275 - Flipping Pancake
Time Limit:
1000ms
Memory limit:
65536kB
题目描述
We start with a stack n of pancakes of distinct sizes. The problem is to convert the stack to one in which the pancakes are in size order with the smallest on the top and the largest on the bottom. To do this, we are allowed to flip the top k pancakes over as a unit (so the k-th pancake is now on top and the pancake previously on top is now in the k-th position).
For example:
http://poj.grids.cn/images/2275_1.jpg
This problem is to write a program, which finds a sequence of at most (2n - 3) flips, which converts a given stack of pancakes to a sorted stack.
输入
Each line of the input gives a separate data set as a sequence of numbers separated by spaces. The first number on each line gives the number, N, of pancakes in the data set. The input ends when N is 0 (zero) with no other data on the line. The remainder of the data set are the numbers 1 through N in some order giving the initial pancake stack.
The numbers indicate the relative sizes of the pancakes. N will be, at most, 30.
输出
For each data set, the output is a single-space separated sequence of numbers on a line. The first number on each line, K, gives the number of flips required to sort the pancakes. This number is followed by a sequence of K numbers, each of which gives the number of pancakes to flip on the corresponding sorting step. There may be several correct solutions for some datasets. For instance 3 3 2 3 is also a solution to the first problem below.
样例输入
3 1 3 2
5 4 3 2 5 1
0
样例输出
3 2 3 2
3 3 4 5
**********************************************************************************/
/**********************************************************************************
解题思路:
http://en.wikipedia.org/wiki/Pancake_sorting
关于Pancake sorting的一种简单情况。就是有种方法可以保证至多2n-3次完成。
类似于选择排序:
先找出n各数字种最大的一个数n,假设所在位置为sn,那么先翻转前sn个数字f(sn),
使得n在最顶部,之后再翻转前n个元素f(n),这样一来n就到了最底部。就是两次翻转。
之后再选择第二大的假设为n-1,位置在sn-1,那么先翻转前sn-1个数字f(sn-1),使得n-1在最
顶部,之后再翻转前n-1个元素f(n-1),这样一来n-1就到了倒数第二个。也是两次翻转。
注意:每次对于第x大的元素要判断它是不是在倒是第x个位置上,若在就不用翻转这个数字了。
一直进行n-2次,最多2n-4次翻转。剩下上面三个最小的1,2其它的都排序了。
分成2种情况,顶多1次搞定:
12:已经有序,不用翻转。
21:一次,f(2)
注意:本题目给定n个数字是1-n,我以为任意n个不等的数字了。其实不用排序,也不用pan2数组的。
**********************************************************************************/
#include <iostream>
#include <cmath>
#include <cctype>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <list>
//#include <stdlib.h>
//#include <iomanip>
using namespace std;
int pan1[31];
int pan2[31];
int ans[60];
//从小到大快速排序
int compare(const void* a, const void* b)
{
int *p1 = (int*)a;
int *p2 = (int*)b;
return *p1 - *p2;
}
int findIndex(int count, int num)
{
for (int i = 1; i <= count; i++)
{
if (pan1[i] == num)
return i;
}
}
int main()
{
int n, index, steps;
cin >> n;
while (n != 0)
{
steps = 0;
for (int i = 1; i <= n; i++)
{
cin >> pan1[i];
pan2[i] = pan1[i];
}
qsort(&pan2[1], n, sizeof(int), compare);
//较大的n-2个
for (int i = n; i > 2; i--)
{
index = findIndex(i, pan2[i]);
if (index == i)
continue;
else if(index == 1)
{
reverse(&pan1[1], &pan1[i+1]);
ans[++steps] = i;
}
else
{
reverse(&pan1[1], &pan1[index+1]);
ans[++steps] = index;
reverse(&pan1[1], &pan1[i+1]);
ans[++steps] = i;
}
}
//最小的2个
if (n == 1)
steps = 0;
else if(pan1[1] > pan1[2])
{
ans[++steps] = 2;
}
cout << steps;
for (int i = 1; i <= steps; i++)
cout << ' ' << ans[i];
cout << endl;
cin >> n;
memset(pan1, 0, sizeof(pan1));
memset(pan2, 0, sizeof(pan2));
}
return 0;
}
2275 - Flipping Pancake
Time Limit:
1000ms
Memory limit:
65536kB
题目描述
We start with a stack n of pancakes of distinct sizes. The problem is to convert the stack to one in which the pancakes are in size order with the smallest on the top and the largest on the bottom. To do this, we are allowed to flip the top k pancakes over as a unit (so the k-th pancake is now on top and the pancake previously on top is now in the k-th position).
For example:
http://poj.grids.cn/images/2275_1.jpg
This problem is to write a program, which finds a sequence of at most (2n - 3) flips, which converts a given stack of pancakes to a sorted stack.
输入
Each line of the input gives a separate data set as a sequence of numbers separated by spaces. The first number on each line gives the number, N, of pancakes in the data set. The input ends when N is 0 (zero) with no other data on the line. The remainder of the data set are the numbers 1 through N in some order giving the initial pancake stack.
The numbers indicate the relative sizes of the pancakes. N will be, at most, 30.
输出
For each data set, the output is a single-space separated sequence of numbers on a line. The first number on each line, K, gives the number of flips required to sort the pancakes. This number is followed by a sequence of K numbers, each of which gives the number of pancakes to flip on the corresponding sorting step. There may be several correct solutions for some datasets. For instance 3 3 2 3 is also a solution to the first problem below.
样例输入
3 1 3 2
5 4 3 2 5 1
0
样例输出
3 2 3 2
3 3 4 5
**********************************************************************************/
/**********************************************************************************
解题思路:
http://en.wikipedia.org/wiki/Pancake_sorting
关于Pancake sorting的一种简单情况。就是有种方法可以保证至多2n-3次完成。
类似于选择排序:
先找出n各数字种最大的一个数n,假设所在位置为sn,那么先翻转前sn个数字f(sn),
使得n在最顶部,之后再翻转前n个元素f(n),这样一来n就到了最底部。就是两次翻转。
之后再选择第二大的假设为n-1,位置在sn-1,那么先翻转前sn-1个数字f(sn-1),使得n-1在最
顶部,之后再翻转前n-1个元素f(n-1),这样一来n-1就到了倒数第二个。也是两次翻转。
注意:每次对于第x大的元素要判断它是不是在倒是第x个位置上,若在就不用翻转这个数字了。
一直进行n-2次,最多2n-4次翻转。剩下上面三个最小的1,2其它的都排序了。
分成2种情况,顶多1次搞定:
12:已经有序,不用翻转。
21:一次,f(2)
注意:本题目给定n个数字是1-n,我以为任意n个不等的数字了。其实不用排序,也不用pan2数组的。
**********************************************************************************/
#include <iostream>
#include <cmath>
#include <cctype>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <list>
//#include <stdlib.h>
//#include <iomanip>
using namespace std;
int pan1[31];
int pan2[31];
int ans[60];
//从小到大快速排序
int compare(const void* a, const void* b)
{
int *p1 = (int*)a;
int *p2 = (int*)b;
return *p1 - *p2;
}
int findIndex(int count, int num)
{
for (int i = 1; i <= count; i++)
{
if (pan1[i] == num)
return i;
}
}
int main()
{
int n, index, steps;
cin >> n;
while (n != 0)
{
steps = 0;
for (int i = 1; i <= n; i++)
{
cin >> pan1[i];
pan2[i] = pan1[i];
}
qsort(&pan2[1], n, sizeof(int), compare);
//较大的n-2个
for (int i = n; i > 2; i--)
{
index = findIndex(i, pan2[i]);
if (index == i)
continue;
else if(index == 1)
{
reverse(&pan1[1], &pan1[i+1]);
ans[++steps] = i;
}
else
{
reverse(&pan1[1], &pan1[index+1]);
ans[++steps] = index;
reverse(&pan1[1], &pan1[i+1]);
ans[++steps] = i;
}
}
//最小的2个
if (n == 1)
steps = 0;
else if(pan1[1] > pan1[2])
{
ans[++steps] = 2;
}
cout << steps;
for (int i = 1; i <= steps; i++)
cout << ' ' << ans[i];
cout << endl;
cin >> n;
memset(pan1, 0, sizeof(pan1));
memset(pan2, 0, sizeof(pan2));
}
return 0;
}