| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 42026 人关注过本帖, 47 人收藏
标题:C论坛算法团队 首战 西安电子科技大学OJ
只看楼主 加入收藏
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
收藏
得分:0 
Problem 1010 - 素数环问题
Problem 1010 - 素数环问题

Time Limit: 1000MS   Memory Limit: 65536KB   Difficulty:
Total Submit: 473  Accepted: 93  Special Judge: No


Description


  有一个由n个数字相连组成的圆环(n<20),组成圆环的数字分别为1,2,3...n-1,n.要求每两个相邻元素的和为素数。(注意:第一个元素始终为1)。


 

Input

n (0<n<20)

Output

要求输出所有符合条件的组成圆环的元素,每个符合条件的圆环按顺时针或者逆时针将元素依次输出,输出格式见样例。要求按字典序输出。
每例以空行分开。

Sample Input

6
8

Sample Output

Case 1:
1 4 3 2 5 6
1 6 5 2 3 4

Case 2:
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2

Hint


Source

Wang Miao
分析
素数环,将1到N的整数排成一圈,使相邻两个数之和为素数。

根据定义对由1到N的整数序列进行深度优先遍历即可。

当遍历到某一个值已经不满足要求可以直接回溯,所以不需要遍历所有状态空间,速度还是很不错的。

根据题目的意思,它给的N值都是可以构成素数环的。但并不是任意的N都可以构成素数环。

比如当N是大于1的奇数时就构不成素数环。为什么?

根据抽屉原理,如果N为奇数(大于1)那么围成一圈后必然有两个不相等的奇数相邻,而两个不相等的奇数的和绝不会是素数。

另外,由于在搜索过程中需要进行大量的素数判断,且题目中N的取值范围不大,所以先准备一张素数表可以减少重复计算提高效率。素数筛在这里应用很合适。
程序代码:
#include<stdio.h>
char np[40];
   
void ring(int n, int d)
{
    static int r[20], f[21];
    int i, t;
    if(d == n)
    {
        if(np[r[n - 1] + 1]) return;
        for(putchar('1'), i = 1; i < n; printf(" %d", r[i++]));
        puts("");
        return;
    }
    if(!d)
    {
        for(i = 0; i < n; f[i] = 0, r[i++] = i + 1);
        ring(n, d + 1);
    }
    else for(i = 2; i <= n; i++)
    {
        if(f[i] || np[i + r[d - 1]]) continue;
        r[d] = i; f[i] = 1;
        ring(n, d + 1);
        f[i] = 0;
    }
}

int main()
{
    int i, j;
    for(i = 2; i < 40; i++)
    if(!np[i]) for(j = i + i; j < 40; j += i) np[j] = 1;
    for(i = 1; scanf("%d", &j) != EOF; i++)
    {
        if(i - 1) puts("");
        printf("Case %d:\n", i);
        ring(j, 0);
    }
    return 0;
}


重剑无锋,大巧不工
2012-10-06 20:54
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
收藏
得分:0 
Problem 1011 - 金子上的友情
Problem 1011 - 金子上的友情

Time Limit: 1000MS   Memory Limit: 65536KB   Difficulty:
Total Submit: 235  Accepted: 76  Special Judge: No


Description


  Wm 和Qinz 是一对好朋友,他俩有着一段伟大的友谊,然而这段友谊是建立在一场残酷的竞争之后的英熊惺惺相惜,那场战斗是这样的
----------------------我------是------华------丽--------的-------分--------割----------线------------------
  地上有三堆金子,第i堆里面a[i]颗金子,每个人轮流从任意一堆金子中取出来任意多颗,当然取出来的颗数不能超过这堆金子的剩余量,现在告诉你这三堆金子每堆的颗数,如果场上三堆金子都剩余0颗的话,没金子可取的那个人要把手中取到的金子全部交给对方,并且对方获胜。
  Wm先取金子,输出最后获胜的人的名字

Input

每行三个数,分别为第一,第二,第三堆金子的颗数(0<=颗数<2^16),题目可能包含多组数据。

Output

输出获胜者的名字

Sample Input

1 1 1
1 2 3


Sample Output

Wm
Qinz

Hint


Source

Wudired
分析
经典博弈问题——尼姆博弈(Nimm Game)。

结论非常简单,如果三堆东西数值的二进制表示的异或结果为0则先拿者输,否则赢。

但结论的推导过程很复杂。如果哪位在不知尼姆博弈为何物的情况下自行得出上面的结论,请一定留下名字。我非常愿意与这样的天才交流。

最后说点题外话。我建议大家,不管将来从事哪个行业,尽力拓宽自己的知识面对你都是有好处的。

不是学会写字就能写好文章,不是学会语言就能编好程序。
程序代码:
#include<stdio.h>
int main()
{
    int a, b, c;
    while(scanf("%d%d%d", &a, &b, &c) != EOF)
    puts(a ^ b ^ c ? "Wm" : "Qinz");
    return 0;
}

重剑无锋,大巧不工
2012-10-07 16:54
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
收藏
得分:0 
Problem 1012 - 奇妙的旅行
Problem 1012 - 奇妙的旅行

Time Limit: 1000MS   Memory Limit: 65536KB   Difficulty:
Total Submit: 279  Accepted: 63  Special Judge: No


Description


  炸鸡儿非常喜欢旅行,而且喜欢在坐标轴上旅行,从起点A到终点B(0<=A,B<=100000)。他旅行的方法很特殊,喜欢用跳的,每次跳一个地方只有三种方法:
从点C跳到点C+1。
从点C跳到点C-1。
从点C跳到点2*C。
请问他从A跳到B至少需要多少步?

Input

每组数据两个整数A,B(0<=A,B<=100000)。

Output

每例输出一行,表示至少需要的步数。

Sample Input

1 100000
0 100000

Sample Output

21
22

Hint


Source

Wang Miao
分析
又是一道搜索题,广搜吧。不过有两个结论可以提高效率减少无效搜索。

1、当a > b时,从a到b需要 a - b 步。

2、当a > (2/3)b时,进行2a这样的步骤无意义,不会比a+1更快接近b。

应该还有更强的结论,甚至怀疑a,b之间存在一个优美的函数关系。留给各位思考吧。
程序代码:
#include<stdio.h>
int cal(int a, int b)
{
    int r[160000] = {}, s[160000], n, mb, i, t, p, q;
    if(a >= b) return a - b;
    mb = b * 2 / 3;
    for(s[0] = a, n = 1, i = 0; i < n && (t = s[i]) - b; i++)
    {
        q = r[t] + 1;
        if(t < b && !r[p = t + 1]) r[s[n++] = p] = q;
        if(t <= mb && !r[p = t << 1]) r[s[n++] = p] = q;
        if(t && !r[p = t - 1]) r[s[n++] = p] = q;
    }
    return r[b];
}
int main()
{
    int a, b;
    while(scanf("%d%d", &a, &b) != EOF) printf("%d\n", cal(a, b));
    return 0;
}


重剑无锋,大巧不工
2012-10-07 19:22
czz5242199
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:小飞侠
威 望:4
帖 子:660
专家分:2400
注 册:2011-10-26
收藏
得分:0 
Problem 1013 - 时间工厂
Problem 1013 - 时间工厂
Time Limit: 1000MS   Memory Limit: 65536KB   Difficulty:
Total Submit: 237  Accepted: 38  Special Judge: No
Description
  zyf总是有很多奇异的想法,他最近常常幻想着以后能开这么一个工厂,可以把前三天里生产出来的东西拿到今天来拼在一起作为今天生产的东西。假如前三天生产出来的产品数分别是x,y,z,那么今天就能生产出x+y+z个。这样一来只要前三天的投入,接下来的工厂每一天都是0成本运作,但产品数却在极速增加,相当暴利。
  当然,为了防止地球被破坏,为了维护世界的和平,zyf是不会让工厂每天生产出来的东西超过1000000006个的,如果超过了,就不停减去1000000007,减到不超过为止。
  现在zyf想知道如果第一、二、三天分别生产a,b,c个产品的话,第n天会生产出多少产品呢?

Input
输入数据的第一行case数。
接下来每一行都有四个数字a,b,c,n(1<=a,b,c,n<=10^9),意义如上文.
Output
对于每个case输出一行,第n天生产的产品数。
Sample Input
2
1 2 3 4
1 1 1 5
Sample Output
6
5
Hint
Source
Qinz

分析
问题等价与一个数列,已知a1,a2,a3,且an=an-1+an-2+an-3,求数列的某一项

由于n有可能过于大,所以直接计算肯定是不行的,我们考虑矩阵:
|an   |   |an-1+an-2+an-3|  | 1 1 1|  |an-1|  |1 1 1|^(n-3)  |a3|
|an-1| =|        an-1        |= | 1 0 0|*|an-2|=|1 0 0|         *|a2|
|an-2|   |        an-2        |   | 0 1 0|  |an-3|  |0 1 0|           |a1|

所以可以通过定义一个矩阵结构,然后通过二分法在logn时间内计算出最后的矩阵,然后直接计算出an

程序代码:
#include <stdio.h>
#include <stdlib.h>
#define Max 1000000007

struct matrix 
{
    long long p[9];
};

struct matrix ans,beg;
int time,n,a,b,c;

void initialize(struct matrix *ans)
{
    ans->p[0]=1; ans->p[1]=1; ans->p[2]=1;
    ans->p[3]=1; ans->p[4]=0; ans->p[5]=0;
    ans->p[6]=0; ans->p[7]=1; ans->p[8]=0;
}

void multi(struct matrix *a,struct matrix b)
{
    struct matrix c;
    c.p[0]=(a->p[0]*b.p[0]+a->p[1]*b.p[3]+a->p[2]*b.p[6])%Max;
    c.p[1]=(a->p[0]*b.p[1]+a->p[1]*b.p[4]+a->p[2]*b.p[7])%Max;
    c.p[2]=(a->p[0]*b.p[2]+a->p[1]*b.p[5]+a->p[2]*b.p[8])%Max;
    
    c.p[3]=(a->p[3]*b.p[0]+a->p[4]*b.p[3]+a->p[5]*b.p[6])%Max;
    c.p[4]=(a->p[3]*b.p[1]+a->p[4]*b.p[4]+a->p[5]*b.p[7])%Max;
    c.p[5]=(a->p[3]*b.p[2]+a->p[4]*b.p[5]+a->p[5]*b.p[8])%Max;
    
    c.p[6]=(a->p[6]*b.p[0]+a->p[7]*b.p[3]+a->p[8]*b.p[6])%Max;
    c.p[7]=(a->p[6]*b.p[1]+a->p[7]*b.p[4]+a->p[8]*b.p[7])%Max;
    c.p[8]=(a->p[6]*b.p[2]+a->p[7]*b.p[5]+a->p[8]*b.p[8])%Max;
    
    int i;
    for (i=0; i<9; i++) a->p[i]=c.p[i];
}

void factorial(int dep)
{
    if (dep==1) initialize(&ans); 
    else if (dep&1)
    {
        factorial(dep>>1); multi(&ans,ans); multi(&ans,beg);
    }
    else
    {
        factorial(dep>>1); multi(&ans,ans);
    }
}

int main()
{
    scanf("%d",&time);
    initialize(&beg);
    while (time--)
    {
        scanf("%d%d%d%d",&a,&b,&c,&n);
        if (n==1) printf("%d\n",a); else
        if (n==2) printf("%d\n",b); else
        if (n==3) printf("%d\n",c); else
        {
            factorial(n-3);
            printf("%lld\n",(ans.p[0]*c+ans.p[1]*b+ans.p[2]*a)%Max);
        }
    }
}
        


[ 本帖最后由 czz5242199 于 2012-10-8 16:55 编辑 ]
收到的鲜花
  • beyondyf2012-10-08 23:41 送鲜花  50朵   附言:漂亮!
2012-10-08 16:54
czz5242199
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:小飞侠
威 望:4
帖 子:660
专家分:2400
注 册:2011-10-26
收藏
得分:0 
Problem 1014 - Uncle Jack
Problem 1014 - Uncle Jack
Time Limit: 1000MS   Memory Limit: 65536KB   Difficulty:
Total Submit: 161  Accepted: 55  Special Judge: No
Description
Dear Uncle Jack is willing to give away some of his collectable CDs to his nephews. Among the titles you can find very rare albums of Hard Rock, Classical Music, Reggae and much more; each title is considered to be unique. Last week he was listening to one of his favorite songs, Nobody’s fool, and realized that it would be prudent to be aware of the many ways he can give away the CDs among some of his nephews.
So far he has not made up his mind about the total amount of CDs and the number of nephews. Indeed, a given nephew may receive no CDs at all
Please help dear Uncle Jack, given the total number of CDs and the number of nephews, to calculate the number of different ways to distribute the CDs among the nephews.

Input
The input consists of several test cases. Each test case is given in a single line of the input by, space separated, integers N (1 ≤ N ≤ 10) and D (0 ≤ D ≤ 25), corresponding to the number of nephews and the number of CDs respectively. The end of the test cases is indicated with N = D = 0.
Output
The output consists of several lines, one per test case, following the order given by the input. Each line has the number of all possible ways to distribute D CDs among N nephews.
Sample Input
1 20
3 10
0 0
Sample Output
1
59049
Hint
Source
5th Xidian University Collegiate Programming Contest(2007.9)

分析
求把D本不同的书分给N个人的分法数目,答案明显是N^D,且看问题规可知最大10^25用long long即可

但是有个坑爹的地方是估计数据组数很多,直接乘的话会超时,用二分法优化即可过

在这里大概讲一下二分法的基本原理,比如我要求2^9,我首先求出2^4,然后把答案平方后再乘一个2,而为了求2^4,先求出2^2,然后把答案平方,一直递归直到求2^0即是递归终点
程序代码:
#include <stdio.h>
#include <stdlib.h>

long long a,b;

long long cal(int b)
{
    if (b==0) return 1; else
    if (b&1)
    {
        long long temp=cal(b/2); return temp*temp*a;
    }
    else
    {
        long long temp=cal(b/2); return temp*temp;
    }
}

int main()
{
    while (scanf("%lld%lld",&a,&b),a!=0) printf("%lld\n",cal(b));
}
        
2012-10-08 17:01
czz5242199
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:小飞侠
威 望:4
帖 子:660
专家分:2400
注 册:2011-10-26
收藏
得分:0 
Problem 1016 - Code
Problem 1016 - Code
Time Limit: 1000MS   Memory Limit: 65536KB   Difficulty:
Total Submit: 40  Accepted: 17  Special Judge: No
Description
Transmitting and memorizing information is a task that requires different coding systems for the best use of the available space. A well known system is that one where a number is associated to a character sequence. It is considered that the words are made only of small characters of the English alphabet a, b, c, ..., z (26 characters). From all these words we consider only those whose letters are in lexigraphical order (each character is smaller than the next character).

The coding system works like this:
• The words are arranged in the increasing order of their length.
• The words with the same length are arranged in lexicographical order (the order from the dictionary).
• We codify these words by their numbering, starting with a, as follows:
a - 1
b - 2
...
z - 26
ab - 27
...
az - 51
bc - 52
...
vwxyz – 83681
...

Specify for a given word if it can be codified according to this coding system. For the affirmative case specify its code.

Input
The input consists of several test cases. For each case, the only line contains a word. There are some constraints:
• The word is maximum 10 letters length.
• The English alphabet has 26 characters.
Output
The output will contain the code of the given word, or 0 if the word can not be codified.
Sample Input
bf
Sample Output
55
Hint
Source
5th Xidian University Collegiate Programming Contest(2007.9)

分析
我们只需算出给定序列之前有多少个序列即可算出给定序列为第几个

首先,如果给定序列长度为len,那么它前面肯定有长度分别为1-len-1的序列,数目分别为C(26,1)...C(26,len-1)

之后开始计算长度为len的序列有多少个排在给定序列的前面,我们假设序列是ceh

明显,a_ _ 和b_ _这种类型的序列肯定排在目标前,他们分别有C(25,2)和C(24,2)个

然后假定第一位就是c了,那么考虑第二位,cd_这种类型的序列肯定符合条件的,他有C(21,1)种

最后假定第二位位e后,符合条件的就只有cef,ceg,ceh共3种了

最后加上自己,就是答案了

程序代码:
#include <stdio.h>
#include <stdlib.h>

int len,ans;
char s[11];

int C(int a,int b)
{
    int i; long long temp=1;
    for (i=1; i<=b; i++) temp*=(a-i+1);
    for (i=1; i<=b; i++) temp/=i;
    return temp;
}

int error()
{
    int i=0;
    while (s[i])
    {
        if (s[i]<'a' || s[i]>'z') return 1;
        i++;
    }
    len=i;
    for (i=0; i<len-1; i++)
      if (s[i]>=s[i+1]) return 1;
    return 0;
}

int main()
{
    int i,j;
    while (scanf("%s",s)!=EOF)
    {
        if (error())
        {
            printf("0\n"); continue;
        }
        ans=0;
        for (i=1; i<len; i++) ans+=C(26,i);
        for (i='a'; i<s[0]; i++) ans+=C('z'-i,len-1);
        for (i=1; i<len; i++)
          for (j=s[i-1]+1; j<s[i]; j++) ans+=C('z'-j,len-i-1);
        printf("%d\n",ans+1);
    }
}
        
2012-10-08 20:27
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
收藏
得分:0 
Problem 1017 - Duan's problem
Problem 1017 - Duan's problem

Time Limit: 1000MS   Memory Limit: 65536KB   Difficulty:
Total Submit: 179  Accepted: 42  Special Judge: No

Duan was a naulty boy. One day, he made a mistake again. His teacher was very angry, and want to punish him. The teacher wanted him to solve a problem. If he successfully solved it, he could go home.

Here is the problem. Duan is given two number a and b. As everybody knows, a number is made of 0-9. The teacher wanted him to count how many 0-9 in a*b, and calculate which one appears more than others.

For example, if a is 100, b is 4, then a*b is 400.
Number 0 1 2 3 4 5 6 7 8 9
Frequency 2 0 0 0 1 0 0 0 0 0
so duan should answer 0.
If a is 110,b is 10,then a*b is 1100
Number 0 1 2 3 4 5 6 7 8 9
Frequency 2 2 0 0 0 0 0 0 0 0
so duan should answer 0 and 1.

Can you help him?

Input

There are multiple test cases.Each case contains two integers a and b (0 <= a < 10^10000, 0<=b<10^9). Input file ends of EOF.

Output

On a single line, print the numbers of largest frequency in incremental order separated by one space.

Sample Input

100 4
110 10

Sample Output

0
0 1

Hint


Source

5th Xidian University Collegiate Programming Contest(2007.9)
分析
题目的要求就是计算a * b中各数字的数量,输出出现次数最多的数字(如果不止一个,则按升序输出所有出现次数最多的)

其中a的取值范围为10^10000,所以算是大数运算吧。但b的取值范围只有10^9,所以难度不大。

想想我们小学时怎么列竖式计算乘法就知道怎么计算了。

简单解释一下我的代码中内层循环中6个for循环的作用,每个for循环完成一组计算

第一个,对c数组清零。c[i]表示数字i出现的次数

第二个,进行大数运算,将运算后的每一位结果累加到c中

第三个,将进位中剩余的量累加到c中

第四个,寻找c中的最大值,这里重用了变量n,之前它用来表示a的长度,现在它表示c中的最大值

第五个,检索到第一个出现次数最多的数字

第六个,按要求输出所有出现次数最多的数字
程序代码:
#include<stdio.h>
#include<string.h>
int main()
{
    char a[10001];
    int b, c[10], n, i;
    long long f;
    for(f = 0; scanf("%s%d", a, &b) != EOF; puts(""))
    {
        for(i = 0; i < 10; c[i++] = 0);
        for(n = strlen(a); n--; c[(f += (long long)b * (a[n] - '0')) % 10]++, f /= 10);
        for(; f; c[f % 10]++, f /= 10);
        for(n = i = 0; i < 10; n < c[i] && (n = c[i]), i++);
        for(i = 0; i < 10 && c[i] < n; i++);
        for(printf("%d", i++); i < 10; c[i] == n && printf(" %d", i), i++);
    }
    return 0;
}

重剑无锋,大巧不工
2012-10-10 15:37
beyondyf
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:103
帖 子:3282
专家分:12654
注 册:2008-1-21
收藏
得分:0 
Problem 1018 - Tour Guide
Problem 1018 - Tour Guide

Time Limit: 1000MS   Memory Limit: 65536KB   Difficulty:
Total Submit: 3  Accepted: 2  Special Judge: No


Description


You are working as a guide on a tour bus for retired people, and today you have taken your regular Nordic seniors to The Gate of Heavenly Peace. You let them have a lunch break where they could do whatever they like. Now you have to get them back to the bus, but they are all walking in random directions. You try to intersect them, and send them straight back to the bus. Minimize the time before the last person is in the bus. You will always be able to run faster than any of the tour guests, and they walk with constant speed, no matter what you tell them. The seniors walk in straight lines, and the only way of changing their direction is to give them promises of camphor candy. A senior will neither stop at nor enter the bus before given such a promise.

Input

A number of test cases consisting of: A line with an integer 1 ≤ n ≤ 8, the number of people on the tour. A line with an floating point number 1 < v ≤ 100, your maximum speed (you start in the bus at the origin). Then follow n lines, each containing four floating point numbers xi yi vi ai, the starting coordinates (−10^6 ≤ xi, yi ≤ 10^6), speed (1 ≤ vi < 100) and direction (0 ≤ ai < 2π) of each of the tour guests.
The input is terminated by a case with n = 0, which should not be processed. All floating point numbers in the input will be written in standard decimal notation, and have no more than 10 digits.

Output

For each test case, print a line with the time it takes before everybody is back in the bus (the origin). Round the answer to the nearest integer. The answer will never be larger than 10^6.

Sample Input

1
50.0
125.0 175.0 25.0 1.96
3
100.0
40.0 25.0 20.0 5.95
-185.0 195.0 6.0 2.35
30.0 -80.0 23.0 2.76
0

Sample Output

20
51

Hint


Source

5th Xidian University Collegiate Programming Contest(2007.9)
分析
先简单翻译一下这一题目。一个导游带着一群北欧来的老人逛天安门。到了天安门后老人们自由活动到处跑,时间到了,导游要把他们全找回到旅游车上。设旅游车及导游、老人在一个平面坐标系内,旅游车所处的位置为坐标原点,老人们处在坐标系的某个点上,并以一个恒定的速度在一个恒定的方向上移动。导游从导游车上出发挨个以一个恒定的速度去寻找这些老人,当他遇到一个老人后给他一块糖(噱头)他便开始以他的速度走回旅游车。现在问直到最后一个老人上车最短需要多少时间。

解这个问题首先要解决的是,当导游处于某一点时,他想找到某一个老人需要的最短时间是多少,以及在哪儿早到这个老人。

解决了这个问题后,我们只需要遍历所有的找法,找出时间最短的即可。



老人的初始坐标、移动速度、移动方向为 x1, y1, v1, d

导游当前的坐标、移动速度和到他从车上出发到现在已经用去的时间为 x0, y0, v0, t0

导游遇到老人时的坐标及他从车上出发到现在所用去的时间为 x, y, t

为了在最短时间内遇到老人,导游应该沿直线移动到相遇点,由此可以建立如下方程组

x = x1 + t * v1 * cos(d)

y = y1 + t * v2 * sin(d)

(x - x0)^2 + (y - y0)^2 = (v0 * (t - t0))^2

解这个方程组即可得到x, y, t。

代码说明

PERSON结构中的d元素,在作为导游时表示当前他已用去的时间,在作为老人时表示老人的移动方向。

intersect函数计算导游g与老人s相遇的时间、地点及老人返回旅游车的时间。

参数mg将返回相遇后g的相应参数,函数返回值为这个老人返回旅游车的时间。

函数sub_cal既是遍历每一种找回老人的方式所用的最少时间,遍历方式即是按照全排列的产生方式确定一个寻找老人的序列,计算在这一序列下所用的最少时间。

函数cal是对sub_cal做了下接口封装。
程序代码:
#include<stdio.h>
#include<math.h>

#define COUNT_MAX    8
#define TIME_MAX    1E7

typedef struct
{
    double x;
    double y;
    double v;
    double d;
}PERSON;

PERSON Senior[COUNT_MAX];
int List[COUNT_MAX];
int N;

double intersect(PERSON g, PERSON s, PERSON * mg)
{
    double c0, c1, c2, vsd, vcd, a, b, c;
    double x, y, t;

    vsd = s.v * sin(s.d);
    vcd = s.v * cos(s.d);
    c0 = g.v * g.v * g.d;
    c1 = s.x - g.x;
    c2 = s.y - g.y;

    a = s.v * s.v - g.v * g.v;
    b = 2 * (c0 + c1 * vcd + c2 * vsd);
    c = c1 * c1 + c2 * c2 - c0 * g.d;

    t = -(b + sqrt(b * b - 4 * a * c)) / (2 * a);
    x = s.x + vcd * t;
    y = s.y + vsd * t;

    mg->x = x;
    mg->y = y;
    mg->v = g.v;
    mg->d = t;

    return t + sqrt(x * x + y * y) / s.v;
}

double sub_cal(PERSON g, double use_t, int deep)
{
    static double min_t;
    double t;
    PERSON mg;
    int i, j, tmp;

    if(deep == 0) min_t = TIME_MAX;
    if(deep == N && min_t > use_t) min_t = use_t;

    for(i = deep; i < N; i++)
    {
        tmp = List[i]; List[i] = List[deep]; List[deep] = tmp;
        t = intersect(g, Senior[List[deep]], &mg);
        if(t < min_t) sub_cal(mg, t > use_t ? t : use_t, deep + 1);
        tmp = List[i]; List[i] = List[deep]; List[deep] = tmp;
    }
    return min_t;
}

double cal(double v)
{
    PERSON g = {0, 0, v, 0};
    return sub_cal(g, 0, 0);
}

int main()
{
    double v;
    int i;
   
    for(i = 0; i < COUNT_MAX; List[i] = i++);
    for(; scanf("%d", &N), N; printf("%.0f\n", cal(v)))
    for(scanf("%lf", &v), i = 0; i < N; i++)
        scanf("%lf%lf%lf%lf", &Senior[i].x, &Senior[i].y, &Senior[i].v, &Senior[i].d);
    return 0;
}
收到的鲜花
  • czz52421992012-10-15 19:37 送鲜花  10朵   附言:这题我一看只有2个人ac,被吓到了,完全没考 ...

重剑无锋,大巧不工
2012-10-12 19:42
czz5242199
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:小飞侠
威 望:4
帖 子:660
专家分:2400
注 册:2011-10-26
收藏
得分:0 
Problem 1019 - The Mailboxes Manufacturers Problem
Problem 1019 - The Mailboxes Manufacturers Problem
Time Limit: 1000MS   Memory Limit: 65536KB   Difficulty:
Total Submit: 33  Accepted: 11  Special Judge: No
Description
In the good old days when Swedish children were still allowed to blowup their fingers with fire-crackers, gangs of excited kids would plague certain smaller cities during Easter time, with only one thing in mind: To blow things up. Small boxes were easy to blow up, and thus mailboxes became a popular target. Now, a small mailbox manufacturer is interested in how many fire-crackers his new mailbox prototype can withstand without exploding and has hired you to help him. He will provide you with k (1 ≤ k ≤ 10) identical mailbox prototypes each fitting up to m (1 ≤ m ≤ 100) crackers. However, he is not sure of how many firecrackers he needs to provide you with in order for you to be able to solve his problem, so he asks you. You think for a while and then say, “Well,if I blow up a mailbox I can’t use it again, so if you would provide me with only k = 1 mailboxes, I would have to start testing with 1 cracker, then 2 crackers, and so on until it finally exploded. In the worst case, that is if it does not blow up even when filled with m crackers, I would need 1 + 2 + 3 + … + m = m × (m + 1) ⁄ 2 crackers. If m = 100 that would mean more than 5000 fire-crackers!” “That’s too many,” he replies. “What if I give you more than k = 1 mailboxes? Can you find a strategy that requires less crackers?”

Can you? And what is the minimum number of crackers that you should ask him to provide you with?

You may assume the following:
1.If a mailbox can withstand x fire-crackers, it can also withstand x − 1 fire-crackers.
2.Upon an explosion, a mailbox is either totally destroyed (blown up) or unharmed, which means that it can be reused in another test explosion.

Note: If the mailbox can withstand a full load of m fire-crackers, then the manufacturer will of course be satisfied with that answer. But otherwise he is looking for the maximum number of crackers that his mailboxes can withstand.

Input
The input starts with a single integer N indicating the number of test cases to follow. Each test case is described by a line containing two integers: k and m, separated by a single space.
Output
For each test case print one line with a single integer indicating the minimum number of fire-crackers that is needed, in the worst case, in order to figure out how many crackers the mailbox prototype can withstand.
Sample Input
4
1 10
1 100
3 73
5 100
Sample Output
55
5050
382
495
Hint
Source
5th Xidian University Collegiate Programming Contest(2007.9)

分析
问题大意是要测定邮箱能承受炸弹的最大数,给定n个邮箱,且最大只测试到m,问用最好的方法最坏情况下需要多少炸弹才能测出

如果邮箱被炸了,就没了,没被炸就能继续用
然后就是如果邮箱能承受k斤炸弹,那么肯定可以承受k-1斤炸弹

题目有点绕,打个比方,1个邮箱,最大测试到10,那么我只能从1开始测,情况最差可能要1,2,3......10的时候才爆炸,这样花费了55斤炸弹,因为只有一个邮箱,如果一下直接测10,直接爆炸了就没邮箱了,就没法测了,而答案确在[1,9]之间。

这题用动态规划,用f[n][p][q]表示n个邮箱,测试从p到q范围的数据 采用最优法最坏情况下需要用的炸弹数量,明显答案就是f[n][1][m]

首先,边界条件是f[1][p][q]=p+(p+1)+....q=(p+q)*(q-p+1)/2

然后求f[n][p][q]时,假设先测试第j个点(p<=j<=q),则有两种情况:
爆炸,此时需要用:f[n-1][p][j-1]+j
没爆炸,则需要   : f[n][j+1][q]+j
由于要求最坏的情况下,所以去他们两中大的那么。

所以就是枚举(p<=j<=q)这所有的点,然后求出所有最大值中的最小值,即为f[n][p][q]

然后就是动态规划无后效性来确定循环顺序,首先n在最外层肯定不变,然后考虑到求f[n][p][q]需要的数据f[n'][p'][q']中q-p>q'-p',所以第二层循环用q-p的差来定,具体实现见代码


程序代码:
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int f[11][102][102],n,m,i,j,p,q,max,min,t_case;
    
    scanf("%d",&t_case);
    while (t_case--)
    {
        scanf("%d%d",&n,&m);
        memset(f,0,sizeof(f));
        
        for (i=1; i<=m; i++)
        {
            f[1][i][i]=i;
            for (j=i+1; j<=m; j++) f[1][i][j]=f[1][i][j-1]+j;
        }
        
        for (i=2; i<=n; i++)
          for (q=0; q<m; q++)
            for (p=1; p<=m-q; p++)
            {
                min=10000;
                for (j=p; j<=p+q; j++)
                {
                    max=(f[i-1][p][j-1]+j>f[i][j+1][p+q]+j)?f[i-1][p][j-1]+j:f[i][j+1][p+q]+j;
                    if (min>max) min=max;
                }
                f[i][p][p+q]=min;
            }
        printf("%d\n",f[n][1][m]);
    }
}
            
    
        


[ 本帖最后由 czz5242199 于 2012-10-15 16:44 编辑 ]
2012-10-15 16:42
czz5242199
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:小飞侠
威 望:4
帖 子:660
专家分:2400
注 册:2011-10-26
收藏
得分:0 
Problem 1020 - Smith Numbers
Problem 1020 - Smith Numbers
Time Limit: 1000MS   Memory Limit: 65536KB   Difficulty:
Total Submit: 278  Accepted: 51  Special Judge: No
Description
Recently, Tiantian found a kind of strange numbers which has the following peculiar property: The sum of the digits of that number was equal to the sum of the digits of the prime factors of that number. Got it? Take 4937775 as the example, this number can be written as the product of its prime factors in the following way:

4937775 = 3 _ 5 _ 5 _ 65837


The sum of all digits of the number is 4+9+3+7+7+7+5 = 42, and the sum of the digits of its prime factors is equally 3+5+5+6+5+8+3+7 = 42. Tiantian was so amazed by his discovery that he named this kind of numbers after his brother: Smith numbers. As this observation is also true for every prime number, Tiantian decided later that a prime number is not worth being a Smith number, so he excluded them from the definition.
Now your task is to determine a given positive integer k is whether the Smith number.
 

Input
The input file consists of a sequence of positive integers, one integer per line. Each integer will have at most 8 digits. The input is terminated by a line containing the number 0.
Output
For every number n > 0 in the input, output ‘Yes’ or ‘No’ to indicate whether n is a Simith number.
Sample Input
4937775
123
0
Sample Output
Yes
No
Hint
Source
6th Xidian University Collegiate Programming Contest(2008.9)

分析
貌似这题没啥可说的,就是把每个数分解之后比较和就行了

不过有个结论,一个数n,对于2..sqrt(n)之间的数全部试除之后,余下的数如果不是1,那么一定是一个>sqrt(n)的素数
        
程序代码:
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int n,sum1,sum2,i,j,p;
    while (scanf("%d",&n),n!=0)
    {
        sum1=0;
        for (j=n; j!=0; sum1+=j%10,j/=10);    
        
        sum2=0; p=n;
        for (i=2; i<=sqrt(n); i++)
          while (n%i==0)
          {
              n/=i;
              for (j=i; j!=0; sum2+=j%10,j/=10);
          }
        if (p==n)
        {
            printf("No\n"); continue;
        }
        if (n!=1)
          for (j=n; j!=0; sum2+=j%10,j/=10);
        
        if (sum1==sum2) printf("Yes\n"); else printf("No\n");
    }
}
        
2012-10-15 17:22
快速回复:C论坛算法团队 首战 西安电子科技大学OJ
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.043563 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved