zoukankan      html  css  js  c++  java
  • 埃及分数&&The Rotation Game&&骑士精神——IDA*

    IDA*:非常好用的搜索,可以解决很多深度浅,但是规模大的搜索问题。

    估价函数设计思路:观察一步最多能向答案靠近多少。

    埃及分数

    题目大意:

      给出一个分数,由分子a 和分母b 构成,现在要你分解成一系列互不相同的单位分数(形如:1/a,即分子为1),要求:分解成的单位分数数量越少越好,如果数量一样,最小的那个单位分数越大越好。

    如:

      19/45 = 1/3 + 1/12 + 1/180;

      19/45 = 1/5 + 1/6 + 1/18;

      以上两种分解方法都要3个单位分数,但下面一个的最小单位分数1/18比上一个1/180大,所以第二个更优。

    题解:
    dfs直接搜爆炸,因为深度无限。

    bfs爆炸,空间不行。

    所以,采用有深度限制的,并且不耗费空间的迭代加深搜索。

    深度即分数的个数。

    配合一下A*思想。

    剪枝:

    1.每次一步到达小于剩余分数的最小分母。

    return b/a+1

    2.如果当前可以选择的分数(已经是最大的)*剩下的步数<剩下的分数,return (A*思想)

    3.如果只剩最后一步,直接判断能否取到。

    对于不能取的处理,开一个数组记录。>1000都可以取的。

    分数运算,手推式子。注意约分

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1000+5;
    ll a,b;
    int k,T;
    bool fl;
    ll ans[N];
    ll mem[N];
    bool no[N];
    int dp;
    ll getfirst(ll a,ll b){
        return b/a+1;
    }
    bool cmp1(ll s1,ll m1,ll s2,ll m2){//s1/m1 > s2/m2 ?
        return (ll)s1*m2>(ll)m1*s2;
    }
    bool cmp2(ll s1,ll m1,ll s2,ll m2){//s1/m1 >= s2/m2 ?
        return (ll)s1*m2>=(ll)m1*s2;
    }
    ll gcd(ll a,ll b){
        return b?gcd(b,a%b):a;
    }
    void sub(ll &s1,ll &m1,ll s2,ll m2){
        s1=s1*m2-s2*m1;
        m1=m1*m2;
        ll g=gcd(s1,m1);
        s1/=g;
        m1/=g;
    }
    bool better(){
        for(int i=dp;i>=dp;i--){
            if(mem[i]!=ans[i]){
                //cout<<mem[i]<<" "<<ans[i]<<endl; 
                return (ans[i]==0)||(mem[i]<ans[i]);
            } 
        } 
        return false;
    }
    void dfs(int now,ll lim,ll rs,ll rm){
        //if(dp<4) cout<<now<<" "<<lim<<" "<<rs<<" "<<rm<<endl;
        if(now==dp){
            if(rs==1){
                if(rm<lim) return;
                //if(rm<=1000&&no[rm]) return;
                fl=true;
                //cout<<" ok "<<endl;
                mem[dp]=rm;
                if(better()){
                ///cout<<"better "<<endl;
                    for(int i=1;i<=dp;i++){
                        //cout<<mem[i]<<" ";
                        ans[i]=mem[i];
                    }//cout<<endl;
                }
                mem[dp]=0;
            }
            return;
        }
        lim=max(lim,getfirst(rs,rm));
        for(int i=lim;;i++){
            if(cmp1(rs,rm,(dp-now+1),i)) return;
                if(cmp2(rs,rm,1,i)){
                    ll hs=rs,hm=rm;
                    sub(hs,hm,1,i);
                    mem[now]=i;
                    dfs(now+1,i+1,hs,hm);
                    mem[now]=0;
                }
        }
    }
    int main(){
            scanf("%lld%lld",&a,&b);
            int t;
            for(int i=1;i<=k;i++){
                scanf("%d",&t);
                no[t]=1;
            }
            fl=false;
            while(!fl){
                dp++;
                //if(dp<4) cout<<dp<<endl;
                dfs(1,2,(ll)a,(ll)b);
            }
            for(int i=1;i<=dp;i++){
                printf("%lld ",ans[i]);
            }
        return 0;
    }
    View Code

     

    The Rotation Game

    每次8种选择吃不消。

    迭代加深直接做。

    A*估价:中间8个数,最多的那一个一次转动最多多一个。如果中间的8个最多的那一个和8的差距比剩余步数多,return

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=9;
    int mp[N][N];
    int st[N][N];
    char sta[10005],top;
    char ans[10005],sum;
    int dp,num;
    bool fl;
    int cnt[4];
    int fan[9]={0,6,5,8,7,2,1,4,3};
    int fin(){
        cnt[1]=cnt[2]=cnt[3]=0;
        for(int i=3;i<=5;i++)
            for(int j=3;j<=5;j++)
                cnt[mp[i][j]]++;
        if(cnt[1]==8) return 1;
        if(cnt[2]==8) return 2;
        if(cnt[3]==8) return 3;
    }
    int che(){
        cnt[1]=cnt[2]=cnt[3]=0;
        for(int i=3;i<=5;i++){
            for(int j=3;j<=5;j++){
                cnt[mp[i][j]]++;
            }
        }
        int big=max(cnt[1],max(cnt[2],cnt[3]));
        return 8-big;
    }
    void mvh(int d){
        if(d==3){
            int tmp=mp[3][7];
            for(int i=7;i>=2;i--) mp[3][i]=mp[3][i-1];
            mp[3][1]=tmp;
        }
        else if(d==4){
            int tmp=mp[5][7];
            for(int i=7;i>=2;i--) mp[5][i]=mp[5][i-1];
            mp[5][1]=tmp;    
        }
        else if(d==7){
            int tmp=mp[5][1];
            for(int i=1;i<=6;i++) mp[5][i]=mp[5][i+1];
            mp[5][7]=tmp;
        }
        else{
            int tmp=mp[3][1];
            for(int i=1;i<=6;i++) mp[3][i]=mp[3][i+1];
            mp[3][7]=tmp;
        }
    }
    void mvz(int d){
        if(d==1){
            int tmp=mp[1][3];
            for(int i=1;i<=6;i++) mp[i][3]=mp[i+1][3];
            mp[7][3]=tmp;
        }
        else if(d==2){
            int tmp=mp[1][5];
            for(int i=1;i<=6;i++) mp[i][5]=mp[i+1][5];
            mp[7][5]=tmp;
        }
        else if(d==5){
            int tmp=mp[7][5];
            for(int i=7;i>=2;i--) mp[i][5]=mp[i-1][5];
            mp[1][5]=tmp;
        }
        else{
            int tmp=mp[7][3];
            for(int i=7;i>=2;i--) mp[i][3]=mp[i-1][3];
            mp[1][3]=tmp;
        }
    }
    bool cmp(){
        for(int i=1;i<=dp;i++){
            if(sta[i]<ans[i]) return true;
            if(sta[i]>ans[i]) return false;
        }
        return false;
    }
    void dfs(int now,int las){
        if(che()>dp-now+1) return;
        if(now==dp+1){
            if(che()==0){
                if(!fl){
                    memcpy(ans,sta,sizeof sta);
                    num=fin();
                }
                else if(cmp()){
                    memcpy(ans,sta,sizeof sta);
                    num=fin();
                }
                fl=true;
            }
            return;
        }
        for(int i=1;i<=8;i++){
            if(i==fan[las]) continue;
            if((i-1)%4>1) mvh(i);
            else mvz(i);
            sta[++top]=i-1+'A';
            dfs(now+1,i);
            sta[top--]=' ';
            if((fan[i]-1)%4>1) mvh(fan[i]);
            else mvz(fan[i]);
        }
    }
    void clear(){
        dp=0;
        fl=false;
    }
    int main(){
        while(1){
            clear();
            scanf("%d",&st[1][3]);
            //cout<<"aa "<<endl;
            if(st[1][3]==0) break;
            scanf("%d",&st[1][5]);
            scanf("%d%d",&st[2][3],&st[2][5]);
            for(int i=1;i<=7;i++) scanf("%d",&st[3][i]);
            scanf("%d%d",&st[4][3],&st[4][5]);
            for(int i=1;i<=7;i++) scanf("%d",&st[5][i]);
            scanf("%d%d",&st[6][3],&st[6][5]);
            scanf("%d%d",&st[7][3],&st[7][5]);
            memcpy(mp,st,sizeof st);
            if(che()==0){
                printf("No moves needed
    ");
                printf("%d
    ",fin());
                continue;
            }
            fl=false;
            while(!fl){
                dp++;
                memcpy(mp,st,sizeof st);
                dfs(1,0);
            }
            printf("%s
    ",ans+1);
            printf("%d
    ",num);
        }
        return 0;
    }
    View Code

    骑士精神

    也许可以折半爆搜。

    但是显然不够漂亮。

    明显“超15步-1”,就迭代加深了。

    估价函数:每次,骑士最多归位一个。如果算上最后一步的空格,可能归位2个。

    所以,当前和终止的差距-1大于剩余步数的话,一定不行。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=6;
    int T;
    char st[6][6];
    int dp;
    bool fl;
    int nd[6][6]={
        {0,0,0,0,0,0},
        {0,1,1,1,1,1},
        {0,0,1,1,1,1},
        {0,0,0,2,1,1},
        {0,0,0,0,0,1},    
        {0,0,0,0,0,0}
    };
    int mp[6][6];
    int mv[8][2]={{-1,+2},{-1,-2},{-2,+1},{-2,-1},{+1,+2},{+1,-2},{+2,-1},{+2,+1}};
    int che(int re){
        int dif=0;
        for(int i=1;i<=5;i++){
            for(int j=1;j<=5;j++){
                dif+=(mp[i][j]!=nd[i][j]);
            }
        }
        if(dif==0) return 2;
        return dp-re+1>=dif-1;    
    }
    void dfs(int now,int x,int y){
        if(!che(now)) return;
        if(fl) return;
        if(now==dp+1){
            if(che(now)==2) {
                fl=true;return;
            }
        }
        for(int i=0;i<8;i++){
            int dx=x+mv[i][0],dy=y+mv[i][1];
            if(dx<1||dx>5) continue;
            if(dy<1||dy>5) continue;
            swap(mp[x][y],mp[dx][dy]);
            dfs(now+1,dx,dy);
            swap(mp[x][y],mp[dx][dy]);
        }
    }
    void clear(){
        fl=false;dp=0;
    }
    int main(){
        scanf("%d",&T);
        while(T--){
            clear();
            int sx,sy;
            for(int i=1;i<=5;i++){
                scanf("%s",st[i]+1);
                for(int j=1;j<=5;j++){
                    if(isdigit(st[i][j]))mp[i][j]=st[i][j]-'0';
                    else {
                        mp[i][j]=2;sx=i,sy=j;
                    }
                }
            }
            fl=false;
            for(dp=0;dp<=15;dp++){
                dfs(1,sx,sy);
                if(fl) break;
            }
            if(fl) printf("%d
    ",dp);
            else printf("-1
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    排序算法(一)冒泡法
    java是传值还是传引用
    赫夫曼树与赫夫曼编码
    数据结构的相关概念
    字符集和字符编码的区别
    redis为什么选择单线程工作模型
    GET和POST请求的核心区别
    MySQL数据类型及后面小括号的意义
    java中的数据类型
    Jedis无法连接centOS7上的redis
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9780322.html
Copyright © 2011-2022 走看看