UVa 10368

来源:互联网 发布:天津大学网络教育专业 编辑:程序博客网 时间:2024/05/21 23:33

题目:有两个数字(a,b),两个人轮流从大的数字上面减去小数字的任意倍数(不能是0),

    两个数字变成倍数时结束,这时轮到的人就是胜利者,给定初始状态,判断谁胜。

分析:博弈,数论。为了简化为题,让a不小于b,否则进行交换。

    对于一个状态<a, b>,其中a = kb+r,那么其实只有反复游戏时,两种可能:

      1.甲留给乙:<b+r,b>,下次乙只能从第一个数中减去b,留给甲<b,r>;

      2.甲留给乙:<b,r>,下次乙的状态为<a1,b1>的子问题,其中a1 = b,b1 = r;

    根据上面分析,构造递归解法f(a,b):

      1.如果是倍数则直接结束;

      2.如果a小于b的二倍(a只能减去1次b),则返回乙的相反结果!f(b,r);

      3.如果乙对于f(b,r)和f(b+r,b)都可以取胜,则一定败北;

      4.其他情况都会胜利(取乙不能失败的子问题即可);

    复杂度:如果每次f(a,b)都会取得f(b+r,b)和f(b,r)两种状态,则复杂度最大;

      T(f(a,b))= T(f(b+r,b))+ T(f(b,r))

               = T(f(b,r))+ 1 + T(f(b,r))

               = 2T(f(b,r))+ 1

               = 2(2T(b1,r1)+ 1)+ 1

               = ...

               = 2^k + 2^k + ... + 1

               = 2^(k+1) - 1

      而计算过程是gcd(a, b),时间复杂度O(lg a)= O(k),因此T(f(a,b))= O(a); 

    优化:这里利用记忆化搜索优化,记录计算过程中的中间结果,采用二维链表存储;

说明:记忆化搜索变得更慢了╮(╯▽╰)╭,没有直接递归的块。

#include <stdio.h>#include <string.h>typedef struct _list_node{int second_value;int state;_list_node *next;}list_node;list_node Node[100000];int list_node_size;typedef struct _list_head{int first_value;_list_head *next;_list_node *second_value_list;}list_head;list_head List[10000], *List_Head;int list_head_size;void list_initial(){list_node_size = 0;memset(Node, 0, sizeof(Node));list_head_size = 0;memset(List, 0, sizeof(List));List_Head = NULL;}int list_find(int a, int b){for (list_head *p = List_Head; p; p = p->next) {if (a == p->first_value) {for (list_node *q = p->second_value_list; q; q = q->next) {if (b == q->second_value) {return q->state;}}}}return -1;}void list_add(int a, int b, int s){list_head *find_first_list = NULL;for (list_head *p = List_Head; p; p = p->next) {if (a == p->first_value) {find_first_list = p;}}if (!find_first_list) {List[list_head_size].next = List_Head;List[list_head_size].first_value = a;List_Head = &List[list_head_size ++];find_first_list = List_Head;}list_node *find_second_list = NULL;for (list_node *q = find_first_list->second_value_list; q; q = q->next) {if (b == q->second_value) {find_second_list = q;}}if (!find_second_list) {Node[list_node_size].next = find_first_list->second_value_list;Node[list_node_size].second_value = b;Node[list_node_size].state = s;find_first_list->second_value_list = &Node[list_node_size ++];}}int f(int a, int b){int ans = list_find(a, b);if (ans != -1) {return ans;}int r = a%b;if (r == 0) {list_add(a, b, 1);return 1;}if (a == b+r) {ans = !f(b, r);list_add(a, b, ans);return ans;}else if (f(b+r, b) && f(b, r)) {list_add(a, b, 0);return 0;}else {list_add(a, b, 1);return 1;}}int main(){int a, b, c;list_initial();while (~scanf("%d%d",&a,&b) && a+b) {if (b > a) {c = b;b = a;a = c;}if (f(a, b)) {printf("Stan wins\n");}else {printf("Ollie wins\n");}}return 0;}