poj2426 Remainder 数学、BFS

一个比较巧妙的题目。
开始以为要用高精度,实在不想打啊,就搜了下解题报告。

点啊点的,开了几个链接,不知怎的就点进了“于娟日记”里的文章。
哎,我惆怅的心情啊。。。。

人太过渺小,
为何我们还无止境地贪求,
能够做好一些,真正重要的事,
生命也就无憾了。

回到题目吧。
高精度嘛,果然是不用的。
利用了一点数学知识。
考虑只有+、-、*的计算,可以发现,只要每次模k,以余数为状态BFS,就能得到结果。
然而有%运算后由于n%m%k不等于n%k%m%k,以模k余数为状态就行不通了。

然后是重点:
因为是求最短序列,所以%只可能出现于两种情况:
1.第一个操作符就是%。因为如果有n+m(n-m)之类的操作,在%之前,则去掉这一段操作它们的结果是一样的。
((n+m)%m=n%m+m%m=n%m)
2.前两个操作符是*%。n*m%m===0。n是啥都不影响,也就是之前的操作无效。
特殊处理这两种情况,再用普通的+、-、*来BFS就解决了。

注意几点:
1.本题的%不是c++中的%,要结果变为正数,可以发现,只要改为(a%b+b)%b即可。
2.输出%这个符号的时候,如果你不是保存在字符变量中,那就要输出"%%"。

感谢这位大牛的题解http://blog.youkuaiyun.com/jackchongs/article/details/10971167


#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define NN 30
#define MM 1010

int tsv[MM],tt[MM],fa[MM],fao[MM],vis[MM];
int asv[MM];

char ch[]={'0','+','-','*','%'};

int mod(int a,int b){return (a%b+b)%b;}

int bfs(int n,int endsta,int k,int m,int func){

    int cnt;
    if (func==0){
        cnt=0;
    }
    else if (func==1){
        cnt=1;tsv[1]=4;
    }
    else if (func==2){
        cnt=2;tsv[1]=3;tsv[2]=4;
    }
    if (n==endsta) return cnt;

    queue<int> q;
    q.push(n);
    memset(vis,0,sizeof(vis));
    vis[n]=1;
    fa[n]=-1;
    fao[n]=-1;
    int u,v;

    while(!q.empty()){
        u=q.front();
        q.pop();
        if (u==endsta) break;
        if (!vis[v=mod(u+m,k)]){
            vis[v]=1;
            q.push(v);
            fa[v]=u;
            fao[v]=1;
        }
        if (!vis[v=mod(u-m,k)]){
            vis[v]=1;
            q.push(v);
            fa[v]=u;
            fao[v]=2;
        }
        if (!vis[v=mod(u*m,k)]){
            vis[v]=1;
            q.push(v);
            fa[v]=u;
            fao[v]=3;
        }
    }
    if (!vis[endsta]) return -1;
    int p=endsta,tc=0;

    while(fa[p]!=-1){
        tt[++tc]=fao[p];
        p=fa[p];
    }
    int i;
    for(i=tc;i>=1;--i){
        tsv[++cnt]=tt[i];
    }
    return cnt;
}


int main(){
    int i;
    int ans,cnt;
    int n,k,m;
    while(1){
        scanf("%d%d%d",&n,&k,&m);
        if (n==0&&k==0&&m==0) break;
        ans=1000000;
        cnt=bfs(mod(n,k),mod(n+1,k),k,m,0);//normal
        if (cnt>0) {
            ans=cnt;
            for(i=1;i<=cnt;++i){
                asv[i]=tsv[i];
            }
        }
        cnt=bfs(0,mod(n+1,k),k,m,2);//*%...
        if (cnt!=-1&&cnt<ans){
            ans=cnt;
            for(i=1;i<=cnt;++i){
                asv[i]=tsv[i];
            }
        }
        cnt=bfs(mod(mod(n,m),k),mod(n+1,k),k,m,1);//%...
        if (cnt!=-1&&cnt<ans){
            ans=cnt;
            for(i=1;i<=cnt;++i){
                asv[i]=tsv[i];
            }
        }
        if (ans>10000) puts("0");
        else {
            printf("%d\n",ans);
            for(i=1;i<=ans;++i){
                printf("%c",ch[asv[i]]);
            }
            printf("\n");
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值