花札洗牌
题目描述
洗牌的方法有很多种。日本纸牌游戏“hanafuda”的洗牌就是这样一个例子。下面是如何执行Hanafuda洗牌。
有一副n张牌。从卡组顶部的第p张卡开始,c卡被拉出并放在卡组顶部,如图1所示。此操作称为切割操作,然后重复进行。
编写一个程序,模拟花花公子洗牌,并回答哪张牌将最终放在牌组顶部。
输入格式
输入包含多组数据。
对于每组数据首先输入一行两个用空格分开的整数n和r,分别是组中的卡数和剪切操作数1≤n≤50,1≤r≤50。
接下来输入r行,每行代表一次切割操作。这些切割操作按列出的顺序执行。每行包含两个正整数p和c(p+c<=n+1)。从卡组顶部的第p张卡开始,c张卡应抽出并放在顶部。
输入以两个用空格分开的0结尾
输出格式
对于每组数据,输出最后在牌堆顶部的牌的编号,牌最初从底部到顶部编号为1-n
题目大意:
有一堆卡片,编号从1.。。n,从第p个卡片开始向后取出c张卡片放到底部。这里的顶部是第n个后边。同时注意的是在将卡片放到顶部的时候,之前在前边的卡片后到后边。
解题思路:
我们用数组来模拟这个过程,我们从前往后存n~1,这个时候下标为1的地方就是顶部。同时用一个额外的数组来存操作后的数据。模拟的过程是将c张卡片放到前面c个位置,然后才将之后的数据填入。
代码:
#include <stdio.h>
#include <cstring>
int game[100];
int n, r;
int main() {
while (~scanf("%d%d", &n, &r)) {
if (!n && !r)
break;
for (int i = 0; i <= n; ++i)
game[i] = n - i + 1;
int barcup[200];
memcpy(barcup, game, sizeof game);
// 以 10 9 8 7 6 5 4 3 2 1 为例
while (r--) {
int p, c;
scanf("%d%d", &p, &c);
// p = 8,c = 3;
// 将第8个开始的3张放到顶部,即 4,3,2
for (int i = p + c - 1, j = c; i >= p; --i, --j)
barcup[j] = game[i];
// 4 3 2 7 6 5 4 3 2 1
// 之后将 第1位到第 p-1 为的元素放到后边
for (int i = c + 1, j = 1; j <= p - 1; i++, ++j)
barcup[i] = game[j];
// 4 3 2 10 9 8 7 6 5 1
memcpy(game, barcup, sizeof game);
}
printf("%d\n", game[1]);
}
return 0;
}
点与圆
在笛卡尔坐标系中已知N个点。你有一个半径为1的圆,并在笛卡尔坐标系中移动它,以便尽可能多地包围这些点。找出有多少点可以同时被包围在最大。当点在圆内或圆上时,它被认为是被圆包围的。
输入
输入由一系列数据集组成,后面跟着一行,只包含一个字符’0’,这表示输入的结束。 每个数据集都以包含整数N的行开始,N表示数据集中的点数。 后面N行描述点的坐标。 每一行都有两个小数X和Y,分别描述点的X和Y坐标。 小数点后保留五位数字。
你可以假设1 <= N <= 300, 0.0 <= X <= 10.0, 0.0 <= Y <= 10.0。 没有两个点之间距离小于0.0001。 数据集中没有两个点的距离近似为2.0。 更准确地说,对于数据集中的任意两点,两者之间的距离d永远不满足1.9999 <= d <= 2.0001。 最后,一个数据集中没有三个点同时非常接近一个半径为1的圆。 更准确地说,让P1, P2, P3是数据集中的任意三个点,d1, d2, d3分别是笛卡尔坐标系中任意点到这三个点的距离。 然后它永远不会同时持有0.9999 <= di <= 1.0001 (i = 1,2,3)。
输出
对于每个数据集,打印单行,其中包含数据集中可以同时被半径为1的圆包围的最大点数。 不应该打印其他字符,包括前导和尾随空格。
解题思路是,将问题转化为特定形式的答案。画个图我们假设有一个圆包含了一推点在里边,我们在可以一直包含所有点的情况下移动圆,我们首先呢圆与其中一个点相交,这个时候是满足的,当与两个点相交的时候,如果还移动圆就无法包含所有的点了。因此极限就是两个点。
因此我们可以枚举两个不同点的组合,通过这两个点算出过这两个点的圆的圆心,之后因为是单位元,遍历所有点如果与圆心的距离在圆内就+1,取这个结果的最大值。
注意事项:
- 一个点的情况,所以我们初始化为1即可。
- 因为题目描述如果两点距离大于2就不计算。
代码:
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
const double eps = 1e-8;
struct point {
double x, y;
} p[3010];
int n;
double dist(point a, point b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
// 已知圆上两点,求圆心坐标
void getmid(point p1, point p2, point ¢er) {
point mid;
mid.x = (p1.x + p2.x) / 2.0;
mid.y = (p1.y + p2.y) / 2.0;
double angle = atan2(p1.x - p2.x, p2.y - p1.y);
double dcm = sqrt(1 - dist(p1, mid) * dist(p1, mid));
center.x = mid.x + dcm * cos(angle);
center.y = mid.y + dcm * sin(angle);
}
int main() {
while (~scanf("%d", &n)) {
if (!n)
break;
for (int i = 1; i <= n; ++i)
scanf("%lf%lf", &p[i].x, &p[i].y);
int ans = 1, cnt = 0;
for (int i = 1; i < n; ++i)
for (int j = i + 1; j <= n; ++j) {
if (dist(p[i], p[j]) > 2.0)
continue;
point center;
getmid(p[i], p[j], center);
int cnt = 0;
for (int k = 1; k <= n; ++k) {
if (dist(p[k], center) < 1.0 + eps)
cnt++;
}
ans = max(ans, cnt);
}
printf("%d\n", ans);
}
return 0;
}
单位分数划分
输入格式
分子为1,分母为正整数的分数称为单位分数。正有理数p/q作为有限多个单位分数之和的表示称为p/q到单位分数的划分。例如,1/2+1/6是将2/3划分为单位分数的一种方式。加法顺序的差异被忽略。例如,我们不区分1/6+1/2和1/2+1/6。
对于给定的四个正整数p、q、a和n,将p/q的分区数计算为满足以下两个条件的单位分数。
划分为最多n个单位分数的总和。
划分中单位分数分母的乘积小于或等于a
例如,如果(p,q,a,n)=(2,3,120,3),能够找到如下四种划分
输入格式
输入不超过1000组数据
对于每组数据,输入p q a n,相邻两个数以空格分开,p,q≤800,a≤12000,n≤7
输入以包含四个用空格分开的0结束
输出格式
对于每组数据,输出一个整数,表示划分方案数
题意:
给了一个分数p/q,求有多少种单位分数之和等于p/q,且满足所有单位分数的分母之积小于等于a,个数小于n。
思路:
分母从1开始枚举,每次记录一下枚举到哪个数了,如果满足分母之ji积小于等于a,且个数不超过n,从此数继续让下搜,因为单位分数之间不分先后顺序,所以这样就涵盖了所有情况。
代码:
#include <stdio.h>
#include <cstring>
int p, q, a, n;
int ans;
void dfs(int p, int q, int mul, int x, int num) {
if (p == 0 && mul <= a) {
ans ++;
return ;
}
// 剪枝
// 分别为 数量达到上限,mul * x 是等会分母要乘的最小
//的的值这都大于 a 了就不用玩了。
// p*x>q*num 就是说因为这一条路径往后分母乘的都>= x
if (num == 0 || mul * x > a || p * x > q * num)
return ;
for (int i = x; i <= a ; ++i) {
if (mul * i <= a) {
int dp = p * i - q; // 不能直接改变p呀不然这一曾就不是以p为根了
if (p >= 0)
dfs(dp, q * i, mul * i, i, num - 1);
}
}
}
int main() {
while (~scanf("%d%d%d%d", &p, &q, &a, &n)) {
if (!p && !q && !n && !a)
break;
ans = 0;
dfs(p, q, 1, 1, n);
printf("%d\n", ans);
}
return 0;
}