HDU 1104 Remainder (BFS求最小步数 打印路径)

题目链接

题意 : 给你N,K,M,N可以+,- ,*,% M,然后变为新的N,问你最少几次操作能使(原来的N+1)%K与(新的N)%k相等。并输出相应的操作。

思路 : 首先要注意题中给的%,是要将负数变为正数的,所以取余的时候要注意,又因为各种问题……

% 的问题是:a mod b = (a % b + b) % b,不是平常的取余。

讨论里有个人是这样说的:

关于此题的用bfs搜索,大家都是知道的。
既然使用了bfs,则队列是少不了的,为了叙述的方便,记运算符集合
    oper = {+,-,*,%}, op = {+,-,*}, pe = {+,-,%}。
N在经过一些列的运算,可能会很大,所以溢出问题,需要考虑充分。
因为最后比较的是两个数对k取余是否相等,因此,在队列中存储对
k取余后的值,各种文章中谈论的都是
   ((n oper m)%k oper m)%k 是不是等于(n oper m oper m)%k
对于op运算是成立的,但是%参与时,结果是不等。例如:
   记n = 2, m = 8, k =3.
   则((n * m)%k % m)%k = 1
   而(n * m % m)%k = 0。
关于另一个结论:%只能出现在第一个位置或者出现在*的后面,且%最多只能出现两次。
   因为对任意n,( n pe m ) % m = n % m. 对于乘法则是不一定的,n * m % m 必为0。
 由于一系列{+,-,%}运算相当于在n的基础上,‘+’相当于加上若干个m,‘-’相当于减去若干
个m,‘%’相当于一次同时减去(或者加上)若干个m。而他们的总和带来的结果就是n的变化是
m的整数倍,所以上面的式子相等。也就是说如果有一个序列中有‘%’,则它的前面要么是空的,
要么是‘*’,因为如果是其他的只会使得操作序列更长。例如:
    +-+-+++%+*+-*-*可以变成%+*+-*-*,后者比前者更短。
    *%+-+-***-+*%+*这样的路径也是不存在的,因为*%使得n为0,而后面的*%也为0,
    重复,所以不会入队列的。
因为‘%’出现的情况很有限,并且出现的位置,也可以知道。特殊处理一下,就可以了。其他的
对k取余没有问题。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <string>
 4 #include <iostream>
 5 #include <queue>
 6 using namespace std ;
 7
 8 struct node
 9 {
10     int step ;
11     int an ;
12     string ch ;
13 } p,q,temp;
14 int vis[1001000] ;
15 int n,m,k,km ;
16 void bfs()
17 {
18     queue<node>Q ;
19     memset(vis,0,sizeof(vis)) ;
20     p.an = (n % km) + km ;
21     vis[p.an] = 1 ;
22     p.step = 0 ;
23     Q.push(p) ;
24     while(!Q.empty())
25     {
26         q = Q.front();
27         Q.pop();
28         if(q.an % k == ((n + 1) % k + k)%k )
29         {
30             printf("%d\n",q.step) ;
31             cout<<q.ch<<endl;
32             return ;
33         }
34         int x = q.an;
35         temp.step = q.step + 1 ;
36         for(int i = 0 ; i < 4 ; i++)
37         {
38             if(i == 0)
39             {
40                 temp.an = (x+m) % km;
41                 temp.ch = q.ch+‘+‘ ;
42             }
43             else if(i == 1)
44             {
45                 temp.an = ((x-m)%km+km)%km;
46                 temp.ch = q.ch+‘-‘ ;
47             }
48             else if(i == 2)
49             {
50                 temp.an = (x*m)%km;
51                 temp.ch = q.ch+‘*‘ ;
52             }
53             else if(i == 3)
54             {
55                 temp.an = (x%m)%km;
56                 temp.ch = q.ch+‘%‘ ;
57             }
58             if(!vis[temp.an])
59             {
60                 Q.push(temp) ;
61                 vis[temp.an] = 1 ;
62             }
63         }
64     }
65     printf("0\n") ;
66 }
67
68 int main()
69 {
70
71     while(~scanf("%d %d %d",&n,&k,&m))
72     {
73         if(n == 0 && m == 0 && k == 0) break ;
74         km = k*m ;
75         bfs() ;
76     }
77     return 0 ;
78 }

				
时间: 2024-11-15 04:34:36

HDU 1104 Remainder (BFS求最小步数 打印路径)的相关文章

HDU 1104 Remainder(BFS路径记录+数论)

Remainder Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4337    Accepted Submission(s): 1095 Problem Description Coco is a clever boy, who is good at mathematics. However, he is puzzled by a d

hdu - 1104 Remainder (bfs + 数论)

http://acm.hdu.edu.cn/showproblem.php?pid=1104 注意这里定义的取模运算和计算机的%是不一样的,这里的取模只会得到非负数. 而%可以得到正数和负数. 所以需要 a mod b = (a % b + b) % b 这样转换得到. 并且,由于新的N可以很大,所以我们每一步都要取%,而且最后要mod k,正常来说每步都%k就行了,但是由于其中的一个操作是N%m,所以我们每一步就不能%k了(%k%m混用会导致%出来的答案错误),而要%(k *m)(其实%(k,

【bfs】hdu 1104 Remainder

[bfs]hdu 1104 Remainder 题目链接:hdu 1104 Remainder 很不错的一道搜索题目,但是有几个关键问题要注意. 最短路径,果断bfs+Queue 路径的存储问题,之前只想把每一步的计算结果存储到queue(int)Q中,后来发现路径无法记录,就选择存储节点的方式并用string保存路径,queue(node)Q,开一个临时的节点node p,每进行一次运算就更新它的路径string+'op',最终输出的一定是完整路径!! 但最关键的是取模!!!!! discus

hdu 1104 Remainder

http://acm.hdu.edu.cn/showproblem.php?pid=1104 a%b=(a%b+b)%b; 题意:开始给了你n, k, m,每次由+m, -m, *m, modm得到新的N,继续对N这样的操作,直到(n+1) mod k== N mod k时结束,并且打印路径 1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <queue> 5

hdu 1104 数论+bfs

题意:给n,m,k;输出n经过+-*%后(n%k+k)%k==((n+1)%k)%k  输出最小路径与运算副 zsd:% 只是求余数 有正负 mod 是求模 无正负. yhd:对m*k求余对 对k求余不对 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 5

One Person Game(扩展欧几里德求最小步数)

One Person Game Time Limit: 2 Seconds      Memory Limit: 65536 KB There is an interesting and simple one person game. Suppose there is a number axis under your feet. You are at point A at first and your aim is point B. There are 6 kinds of operations

POJ 1753 Flip Game (高斯消元 枚举自由变元求最小步数)

题目链接 题意:4*4的黑白棋,求把棋全变白或者全变黑的最小步数. 分析:以前用状态压缩做过. 和上题差不多,唯一的不同是这个终态是黑棋或者白棋, 但是只需要把给的初态做不同的两次处理就行了. 感觉现在还只是会套模板,不能独立的思考,好伤心.... 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath&g

Hdu 1358 Period (KMP 求最小循环节)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1358 题目描述: 给出一个字符串S,输出S的前缀能表达成Ak的所有情况,每种情况输出前缀的结束位置和k. 解题思路: 打表算出next数组,然后对位置i求循环节,如果满足 i % (i - Next[i]) == 0 && Next[i] != 0,所对应的循环节(i - Next[i]), 循环次数是i / (i - Next[i]) 1 #include<cstdio> 2

hdu 2923 floyd一次性求最小边

#include <stdio.h> #include <string> #include <iostream> #include <queue> #include <map> using namespace std; #define INF 0x7fffff #define MAX 200 int path[MAX][MAX]; int arry[10000]; map<string, int>list; map<string