#include <stdio.h>
#include <stdlib.h>
int n;
static int visited[20];
static int stack[20];
int top;
int prime[38] = {0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,1};
void dfs (int i,int top)
{
stack[top] = i;
if (top == n - 1)
{
for (int m = 2; m <= n; m ++)
{
if (prime[stack[top] + m] && prime[m + 1] && !visited[m])
{
stack[top + 1] = m;
//printf ("%d\n",m);
for (m = 1; m <= n; m ++)
{
printf (m == 1 ? "%d" :" %d", stack[m]);
}
printf ("\n");
}
}
}
else
{
for (int j = 1; j <= n; j ++)
{
if (prime[i + j] && !visited[j])
{
visited[j] = 1;
dfs (j,top+1);
visited[j] = 0;
}
}
}
}
int main ()
{
int cn = 0;
while ( scanf ("%d", &n) != EOF )
{
printf ("Case %d:\n",++ cn);
visited[1] = 1; top = 1;
dfs (1,top);
printf ("\n");
}
return 0;
}
posted @
2010-08-18 14:25 雪黛依梦 阅读(413) |
评论 (0) |
编辑 收藏
//这个题目如果用普通的求模求余方法做一定会超时的
//关键是发现数字的规律,当位数之和 > 10 时 其实减去 9 就是位数之和
//采用字符输入便于求和计算,同时处理了大数问题
数组应开的比较大
1#include <stdio.h>
2#include <stdlib.h>
3
4int main ()
5{
6 char s[999];
7
8 int i , sum;
9
10 while (scanf ("%s",s) && s[0] != '0')
11 {
12 for (i = sum = 0; s[i]; i ++)
13 {
14 sum += s[i] - '0';
15 }
16
17 printf ("%d\n", sum%9 == 0 ? 9 : sum %9);
18 }
19 return 0;
20}
21
posted @
2010-08-16 11:37 雪黛依梦 阅读(160) |
评论 (0) |
编辑 收藏
//解题思路:每一个立方体必然有 3 个面积,所以 N 种类型的立方体,必然有 3 * N 个面积组合
//将所有的面积从小到大排列之后,每组面积必然对应一个高的值,依据题意,要使高之和最大,所
//以这个问题就转化成了求最长子列和的最大值
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5//定义一个结构体存立方体的面积 和 边长
6struct cube
7{
8 int x;
9 int y;
10 int z;
11 int area;
12}b[200]; //结构体变量
13
14//这是调用qsort 函数时必须要用的
15int compare(const void* a,const void* b)
16{
17 return (*(cube *)a).area-(*(cube *)b).area; //如果 < 则返回负数 如果 = 则返回0 如果 > 则返回 1
18}
19
20// 判断上面的两条边都要 < 下面的两条边
21int com (cube a, cube b)
22{
23
if ( (a.x < b.x && a.y < b.y) || (a.y < b.x && a.x < b.y) ) 如:10 20 与 40 50
24
return 1;
25
26
else
27
return 0;
28
}
29
30int main ()
31{
32 int sum[200];
33
34 //用来控制下标的
35 int dir[3][3] = { {0, 1, 2}, {0, 2, 1}, {1, 2, 0} };
36
37 int n;
38 int a[3];
39 int count = 0;
40 while (scanf ("%d", &n))
41 {
42 if (!n)
43 break;
44 int num = 0;
45 memset (sum, 0, sizeof (sum));
46 for (int i = 0; i < n; i ++)
47 {
48 scanf ("%d%d%d", &a[0], &a[1], &a[2]); //读入输入的三个数据
49
50 for (int j = 0; j < 3; j ++) //将所有可能的 立方体构成 存入到数组 b 中
51 {
52 b[num].x = a[ dir[j][0] ];
53 b[num].y = a[ dir[j][1] ];
54 b[num].z = a[ dir[j][2] ];
55 b[num].area = b[num].x * b[num].y;
56 num ++; //错点
57 }
58
59 }
60
61 //对 b 数组按面积进行快速排序
62 qsort (b, n * 3, sizeof (b[0]), compare);
63
64 /**//*
65 测试排序是否正确
66 for (int i = 0; i < 3 * n; i ++)
67 {
68 printf ("%d\t%d\t%d\t%d\n",b[i].x, b[i].y, b[i].z, b[i].area);
69 }*/
70
71 //在满足题目条件:上面的两条边都要 < 下面的两条边的情况下找到最大的高的和
72 sum[0] = b[0].z;
73 for (int i = 1; i < 3 * n; i++)
74 {
75 int temp = 0;
76 for (int j = 0; j < i; j ++)
77 {
78 if ( sum[j] > temp && ( com(b[j],b[i]) ) ) //要比较的高的值 满足题目的条件 累加求和
79 {
80 temp = sum[j];
81 }
82 }
83 sum[i] = temp + b[i].z;
84
85 //printf ("%d\t",sum[i]);
86 }
87
88 //printf ("\n");
89
90 //输出高的和
91 int max = -1;
92 for (int i = 0; i < 3 * n; i ++)
93 {
94 if (max < sum[i])
95 max = sum[i];
96 }
97
98 printf ("Case %d: maximum height = %d\n", ++count , max);
99
100 }
101
102 return 0;
103}
104
posted @
2010-08-16 10:03 雪黛依梦 阅读(709) |
评论 (0) |
编辑 收藏
DP 问题的关键在于:如何分解子问题以及求得子问题的最优解
//这题可以看成0,1...n,n+1一共n+2个终点站包括起始点,分别求出到达每个站的最短时间即可
//第 i 站时用前面的timeT[i - 1] + 后面的可能解,由于timeT保存的是到该站时的最短时间,所以不断递归 i 之至 n 就可以求得最优解
//dp[i]=dp[i-1]+f(i-1,i)(即i-1,到i的最短时间)
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int L;
int N, C, T;
int vr, vt1, vt2;
int p[103]; //记录各站p[i]到起点的距离
double timeT[103]; //记录第i段的最短时间
double timeR;
while ( scanf ("%d",&L) != EOF )
{
scanf ("%d%d%d", &N , &C, &T);
scanf ("%d%d%d", &vr, &vt1, &vt2);
//兔子的时间
timeR = L * 1.0 / vr;
//记录各站p[i]到起点的距离
p[0] = 0;
p[N + 1] = L;
for (int i = 1; i <= N; i ++)
{
scanf ("%d", &p[i]);
}
//找到p[i] 到 p[i + 1]段的最短耗时
timeT[0] = 0; //递归出口
double len;
double e, min;
for (int i = 1; i <= N + 1; i ++)
{
min = 9999999.9;
for (int j = 0; j < i; j ++)
{
len = p[i] - p[j];
if (len > C)
e = ( 1.0 * C / vt1 ) + (len - C + 0.0) * 1.0 / vt2 ;
else
e = len * 1.0 / vt1 ;
e += timeT[j];
if (j)
e += T;
if ( e < min)
min = e;
}
timeT[i] = min;
}
if (timeT[N + 1] < timeR)
{
printf ("What a pity rabbit!\n");
}
else
printf ("Good job,rabbit!\n");
}
return 0;
}
posted @
2010-08-15 16:16 雪黛依梦 阅读(257) |
评论 (0) |
编辑 收藏
//思路:分析易知递推关系式:dp[i][j] = (i - r)* r + dp[r][k] // r条自由线和i - r条平行线的交点数 + r条直线本身的交点数
// dp[i][j]表示 i 条直线可能的交点种数 j = (i - r)* r + dp[r][k]
// r表示自由线的条数,(i - r)表示平行线的条数,(i - r)* r 表示平行线和自由线的交点个数
// r 可以取 0 -- i - 1 但是这里初始化的缘故循环时 r 取 1 -- i - 1
// dp[r][k]表示 r 条直线本身的交点个数
// max i 条直线最多的交点数
// 先把i条直线0个交点的情况初始值为1(这是一定的),然后若i-r条直线有j个交点则i条直线必有(i-r)*r+j个交点,标记为 1
// 通过标记为 1 的下标 j 为 n 取 i 时的交点数
本题的巧妙之处在于:将下标对应为交点种类输出,同时又满足了从小到大输出这个条件
posted @
2010-08-15 10:02 雪黛依梦 阅读(464) |
评论 (0) |
编辑 收藏
//本题是在 grids 2757的基础上得到解决的,即找到最大子例的和
// sum[i] 用于存放到 i 位置为止的子序列的和,所以只需要找到前i - 1 中的sum 所存的最大值再加上本身就可以了
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int b[1001];
int n;
__int64 sum[1001]; //用于存放到 i 位置为止 的子序列的和
while (scanf ("%d", &n) && n)
{
for ( int i = 0; i < n;i ++)
{
scanf ("%d", &b[i]);
}
sum[0] = b[0];
for (int i = 1; i < n; i ++) //下面的处理和 grids 2757的处理思想是一样的,只不过sum 数组存的是和值
{
int tempMaxsum = 0;
for (int j = 0; j < i; j ++) //因为 i 之前的和值已经存储在了sum中,
// 所以只需要找到最大的tempMaxSum后再加上 i 位置本身的值就可以了
{
if (b[j] <b[i] && tempMaxsum < sum[j])
{
tempMaxsum = sum[j];
}
}
sum[i] = tempMaxsum + b[i];
}
__int64 max = -1;
for (int i = 0; i < n; i ++)
{
if (max < sum[i])
{
max = sum[i];
}
}
printf ("%I64d\n",max);
}
return 0;
}
posted @
2010-08-14 21:35 雪黛依梦 阅读(768) |
评论 (0) |
编辑 收藏
//动态规划题目最重要的一点是如何将问题分解得到子问题,并且将子问题解决
//本题以下标为状态量,找到以该下标位置 i 为终点时的最长子列:如果 i 位置的值 > i - 1位置的值,则长度加 1 ,
//所以利用判断大小来递归,出口是:下表为 0 时,长度为 1
//利用 nMaxLen【i】记录长度避免了重复计算
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ()
{
int n;
int b[1000];
int nMaxLen[1000];
while (scanf ("%d", &n) != EOF && 1 <= n && n <= 1000)
{
memset (nMaxLen, 0 ,sizeof(nMaxLen));
//将输入的数值存入数组 b 中
for (int i = 0; i < n; i ++)
{
scanf ("%d", &b[i]);
}
//找到每一个状态下标 i 对应的最大子列长度,并将其存入数组nMaxLen[]中
nMaxLen[0] = 1;
for (int i = 1; i < n; i ++)
{
int temp = 0;
for (int j = 0; j < i ; j ++)
{
if ( b[i] > b[j])
{
if (temp < nMaxLen[j]) //只有当当前的长度 < 之前一位数的序列长时才可以赋值,最后起到 temp + 1 的作用
// 为什么:最大序列可能出现在 j 之后如: 7 9 10 6 11
temp = nMaxLen[j];
}
}
nMaxLen[i] = temp + 1;
}
//遍历数组nMaxLen从中读出最大值,即:在该位置时取得最大的子序列
int max = -1;
for (int i = 0; i < n; i ++)
{
if (nMaxLen[i] > max)
max = nMaxLen[i];
}
printf ("%d\n", max);
}
//system ("pause");
return 0;
}
posted @
2010-08-14 15:38 雪黛依梦 阅读(184) |
评论 (0) |
编辑 收藏
/*解题思路和1297类似:都是通过递推第 n --- 1 种情况合法与不合法,从而知道第 n 种
如下:
设lock[i]表示:有 i个槽的钥匙的个数
设one[i]表示:有 i个槽且左边第一个槽深度为1的钥匙的个数
设two[i]表示:有 i个槽且左边第一个槽深度为2的钥匙的个数
..
..
设six[i]表示:有 i个槽且左边第一个槽深度为6的钥匙的个数
则显然:lock[i]=one[i]+two[i]+ three[i]+four[i]+five[i]+six[i]
由于易知:one[i]=six[i],two[i]=three[i]=four[i]=five[i]
则可以得到:lock[i]=one[i]*2+two[i]*4
当左边第一个凿深是1 或 2 时 与后面的 i - 1 种不合法的情况结合必须构成合法的,由此递推开来
其中:
one[i]=one[i-1]+two[i-1]+three[i-1]+four[i-1]+five[i-1]+a[i]; //可理解为所有LOKE(i-1)前加1,
所以后面的不能出现six【i - 1】,否则1 6相邻
=one[i-1]+two[i-1]*4 +a[i] //而a[i]即为不成立的LOKE(i-1),b[i]同理
two[i]=one[i-1]*2+two[i-1]*4 +b[i]
其中,a[i] 和b[i]的含义分别是:
a[i]表示“有 i个槽且左边第一个槽深度为1,同时这种钥匙在除掉第一个槽后不再是钥匙”的钥匙的个数。
例如 123,124,125,134,135,145,126,136,146,156 就属于这种情况。
b[i]表示“有 i个槽且左边第一个槽深度为2,同时这种钥匙在除掉第一个槽后不再是钥匙” 的钥匙的个数。
分析到这里,可以知道,关键的是求a[i]和b[i],我们可以得到如下表达式:
a[i]=(2^(i-1)-2)*6+(2^(i-2)-1)*4
b[i]=(2^(i-1)-2)*9
其中,a[i] 的各部分的含义如下:
(2^(i-1)-2)*6:
当去掉第一位,后面i-1位只有 (2,3)或者 (2,4) 或者(2,5) 或者(3,4) 或者(3,5) 或者(4,5)两种数字的时候,
显然是不合法的钥匙(不满足至少有3个不同的深度),加上第一位的1则显然是一个合格的钥匙。所以后面的数
字可以为一个组合中两个数字的任意一个,根据乘法原理i-1位一共有2^(i-1)种组合,当然还需要去掉两种特殊
情况,就是后面i-1位完全相同的情况。满足这种条件的一共有上面六种组合,所以得到(2^(i-1)-2)*6。
(2^(i-2)-1)*4:
当去掉第一位,后面i-1位只有 (2,6)或者 (3,6) 或者(4,6) 或者(5,6)两种数字的时候,显然是不合法的钥匙
(不满足至少有3个不同的深度),加上第一位的1则“可能”是一个合格的钥匙。因为要注意满足“相连的槽其
深度之差不得为5”这个条件,所以,紧跟着1的绝对不能是6,这样,相对于上面的分析,后面i-2位可以是每组
中的任意一个,所以有2^(i-2),还要减去1是因为同样要排除后面全部是和第2位一样的数字这样的情况。满足
这种条件的一共有上面的四种组合,所以得到(2^(i-2)-1)*4。
b[i] 的含义如下:
(2^(i-1)-2)*9:
当去掉第一位,后面i-1位只有 (1,3)或者 (1,4) 或者(1,5) 或者(3,4) 或者(3,5) 或者(3,6) 或者(4,5) 或者(4,6)
或者(5,6) 两种数字的时候,显然是不合法的钥匙(不满足至少有3个不同的深度),加上第一位的1则显然是一个合
格的钥匙。所以后面的数字可以为一个组合中两个数字的任意一个,根据乘法原理i-1位一共有2^(i-1)种组合,当然
还需要去掉两种特殊情况,就是后面i-1位完全相同的情况。满足这种条件的一共有上面9种组合,所以得到(2^(i-1)-2)*9。
(排除(1,6)是因为这样的不合法情况和前面的第一个凿 2 相结合后组成的钥匙还是不合法的)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
__int64 Lock[26]; //凿深为 i 时的可能钥匙种类
__int64 one[26]; //当左边第一个凿深为 1 时的可能钥匙种类
__int64 two[26]; //当左边第一个凿深为 2 时的可能钥匙种类
__int64 a[26]; //当左边第一个凿深为 1 时,后面的 i - 1 中可能的不合法情况
__int64 b[26]; //当左边第一个凿深为 1 时,后面的 i - 1 中可能的不合法情况
int main ()
{
one[3] = 16;
two[3] = 18;
Lock[3] = 104;
for (int i = 4; i < 26; i ++)
{
a[i] = 16 * (pow (2, i - 2) - 1);
b[i] = 9 * (pow (2, i - 1) - 2);
one[i] = one[i - 1] + 4 * two[i - 1] + a[i];
two[i] = 2*one[i - 1] + 4 * two[i - 1] + b[i];
Lock[i] = 2 * one[i] + 4 * two[i];
}
for (int i = 3;i < 26; i ++)
{
printf("N=%d: %I64d\n", i, Lock[i]);
}
system ("pause");
return 0;
}
posted @
2010-08-14 14:01 雪黛依梦 阅读(228) |
评论 (0) |
编辑 收藏
//利用aMaxSum来标记该位置坐标上的值是否被计算过了,如果被计算了直接利用原来已经存在aMaxSum中的值
//递归是一个比较难以理解的知识,最好的方法是自己通过画出递归调用图来理解中间的过程
//动态规划是以递归为基础的,需要解决的是将递归中出现的重复子问题记录下来,以减少下次递归时的重复计算从而减少时间复杂度;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int a[101][101];
int n;
int aMaxSum[101][101];
int max_sum (int r,int j)
{
if ( r == n - 1)
return a[r][j];
if (aMaxSum[r + 1][j] == -1)
aMaxSum[r + 1][j] = max_sum (r + 1, j);
if (aMaxSum[r + 1][j + 1] == -1)
aMaxSum[r + 1][j + 1] = max_sum (r + 1, j + 1);
if ( aMaxSum[r + 1][j] > aMaxSum[r + 1][j + 1])
return aMaxSum[r + 1][j] + a[r][j];
else
return aMaxSum[r + 1][j + 1] + a[r][j];
}
int main ()
{
while ( scanf ("%d", &n) != EOF )
{
for (int i = 0; i < n; i ++)
{
for (int j = 0; j < i+ 1; j ++ )
{
scanf ("%d", &a[i][j]);
}
}
memset (aMaxSum, -1, sizeof (aMaxSum));
int max = max_sum (0,0);
printf ("%d\n", max);
}
return 0;
}
posted @
2010-08-14 10:54 雪黛依梦 阅读(124) |
评论 (0) |
编辑 收藏
#include <stdio.h>
#include <stdlib.h>
int main ()
{
__int64 mi[50];
mi[0]=0;
mi[1] = 1;
mi[2] = 2;
for (int i = 3; i < 50; i ++)
{
mi[i] = mi[i - 2] + mi[i - 1];
}
int n;
int a, b;
while ( scanf ("%d", &n) != EOF )
{
for (int i = 0; i < n; i ++)
{
scanf ("%d%d", &a, &b);
printf ("%I64d\n",a < b ? mi[b - a]: 0);
}
}
return 0;
}
//关键是弄清楚问题的本质:因为达到 b 是有两条路径的 由此递推
posted @
2010-08-13 21:31 雪黛依梦 阅读(221) |
评论 (0) |
编辑 收藏