zoukankan      html  css  js  c++  java
  • 迭代,IDA*

    1.codevs1288

    题意:对于一个分数a/b(a!=1),将它表示为1/x + 1/y + 1/z ……的形式,x,y,z……互不相同

    多解取加数少的,加数相同时,取最小的分数最大的。

    思路:经典基础IDA*

    搜索无指定界限所以手动规定。因为要求分母尽量小,所以先找最小分母做下界
    然后规定层数迭代搜 ans存分母
    因为从小到大依次搜,层数加深,第一次找到的一定最优。
    估价函数:若扩展到i层时,前i个分数之和为c/d,第i个分数为1/e
    因为分母递增,所以接下来至少还需要>(a/b-c/d)/(1/e)个分数,总和才能到a/b.
    此估价函数可以估计出最少多少步可以到达解,也就是说限定了层数。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    #define N 10001
    #define ll long long
    
    using namespace std;
    
    int minn;
    ll a,b,deep;
    ll ans[N],v[N];
    
    inline ll read()
    {
        ll x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;    
    }
    
    inline ll gcd(ll x,ll y)
    {
        if(x<y) x^=y,y^=x,x^=y;
        int tmp;
        while(y){
            tmp=x%y;x=y;y=tmp;
        }return x;
    }
    
    inline bool better(int d)
    {
        for(int i=d;i>=0;i--)
          return ans[i]==-1 || v[i]<ans[i];
        return false;
    }
    
    inline int get(ll x,ll y)//当前下界 
    {
        for(int i=2;;++i) if(y<x*i) return i;
    }
    
    bool IDA(int d,int minn,ll aa,ll bb)
    {
        if(d==deep)
        {
            if(bb%aa) return false;//分子必须是1.因为已经约分,不必但心aa不为1 
            v[d]=bb/aa;
            if(better(d)) memcpy(ans,v,sizeof(ll)*(d+1)); 
            return true;
        }
        bool flag=false;
        minn=std::max(minn,get(aa,bb));//也算剪枝,minn在不断增大 
        for(int i=minn;;++i)
        {
            if(bb*(deep-d+1)<=i*aa) break;
    //估价函数:因为i在增大,所以如果剩下的deep-d+1个分数全部都是1/i,加起来仍然不超过aa/bb,则无解,需要阔搜索层数 
            v[d]=i;
            ll b2=bb*i,a2=aa*i-bb;//计算aa/bb-1/i
            ll g=gcd(a2,b2);
            if(IDA(d+1,minn+1,a2/g,b2/g)) flag=true;
        }
        return flag;
    }
    
    int main()
    {
        a=read();b=read();
        minn=get(a,b);
        for(deep=1;;deep++)
        {
            memset(ans,-1,sizeof ans);//don't forget
            if(IDA(0,get(a,b),a,b))//get 得到搜索下界 
              break;
        }
        for(int i=0;i<=deep;++i) printf("%d ",ans[i]);
        return 0;
    }
    
    Code
    Code

    2.codevs 2541

    题意:给定n计算m^n的最少运算次数。在运算的每一步,都应该是m的正整数次方

    思路:迭代加深

    同样的维护已经得到的mi数组
    数组的大小对应做了几次运算
    加上几个剪枝:
    如果mi中最大的<<(deep-k) 都到不了n 搜索失败
    生成新的mi的时候 尽量组合数大的 这样也可以减小规模

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    #define N 101
    
    using namespace std;
    int n,a[N<<2];
    
    int dfs(int k,int deep)
    {
        if(a[k]==n) return deep;
        if(deep==k) return 0;
        int maxx=0;
        for(int i=0;i<=k;i++)maxx=max(maxx,a[k]);
        if(maxx<<(deep-k)<n)return 0;
        for(int i=k;i>=0;i--)
        {
            a[k+1]=a[k]+a[i];
            if(dfs(k+1,deep)) return 1;
            a[k+1]=a[k]-a[i];
            if(dfs(k+1,deep)) return 1;
        }return 0;
    }
    
    int main()
    {
        scanf("%d",&n);
        if(n==1)
        {
            printf("0
    ");
            return 0; 
        }
        a[0]=1;
        for(int i=1;i<=N;i++)
          if(dfs(0,i))
          {
              printf("%d
    ",i);
              return 0;
          } 
        return 0;
    }
    Code

    3.codevs2495题意:

    地毯上的格子有N行N列,每个格子用一个0~5之间的数字代表它的颜色。  水叮当可以随意选择一个0~5之间的颜色,然后轻轻地跳动一步,左上角的格子所在的联通块里的所有格子就会变成她选择的那种颜色。这里连通定义为:两个格子有公共边,并且颜色相同。想知道最少要多少步才能把所有格子的颜色变成一样的。

    思路:

    左上角的格子所在的联通块里的格子标记为1。左上角联通块周围一圈格子标记为2,
    其它格子标记为0。如果某次选择了颜色c,
    只需要找出标记为2并且颜色为c的格子,向四周扩展
    ,并相应地修改v标记,就可以不断扩大标记为1的区域,
    最终如果所有格子标记都是1

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    
    using namespace std;
    int s,n,map[9][9],mark[9][9];
    int xx[4]= {1,-1,0,0},yy[4]= {0,0,-1,1},used[6];
    bool ans;
    
    int get()
    {
        int t=0;
        memset(used,0,sizeof(used));
        for(int i=1; i<=n; i++)
          for(int j=1; j<=n; j++)
            if(!used[map[i][j]]&&mark[i][j]!=1)
            {
                used[map[i][j]]=1;
                t++;
            }return t;
    }
    
    void dfs(int a,int b,int x)
    {
        mark[a][b]=1;
        for(int i=0; i<4; i++)
        {
            int nowx=a+xx[i],nowy=b+yy[i];
            if(nowx<1||nowy<1||nowx>n||nowy>n||mark[nowx][nowy]==1)continue;
            mark[nowx][nowy]=2;
            if(map[nowx][nowy]==x)dfs(nowx,nowy,x);
        }
    }
    
    int fill(int x)
    {
        int t=0;
        for(int i=1; i<=n; i++)
          for(int j=1; j<=n; j++)
            if(mark[i][j]==2&&map[i][j]==x) {t++;dfs(i,j,x);}
        return t;
    }
    
    void search(int k)
    {
        int v=get();
        if(!v)ans=1;
        if(k+v>s||ans)return;
        int temp[10][10];
        for(int i=0; i<=5; i++)
        {
            memcpy(temp,mark,sizeof(mark));
            if(fill(i))search(k+1);
            memcpy(mark,temp,sizeof(mark));
        }
    }
    
    int main()
    {
        while(1)
        {
            memset(mark,0,sizeof(mark));
            scanf("%d",&n);
            ans=0;
            if(n==0)break;
            for(int i=1; i<=n; i++)
                for(int j=1; j<=n; j++)
                    scanf("%d",&map[i][j]);
            dfs(1,1,map[1][1]);
            for(s=0;;s++)
            {
                search(0);
                if(ans){printf("%d
    ",s); break;}
            }
        }
        return 0;
    }
    Code
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    windows程序设计第四章 system2.c 新增滚动条功能
    const指南
    转:android listView 继承ListActivity的用法
    iPhone使用委托在不同的窗口之间传递数据
    (PHP) imagecreatefrombmp 从 BMP 文件或 URL 新建一图像
    iPhone解析非UTF8的XML
    php生成略缩图(转载)
    iphone下载进度条,显示下载字节数与百分比
    android中实现消息推送
    Android动画开发——Animation动画效果
  • 原文地址:https://www.cnblogs.com/L-Memory/p/7403043.html
Copyright © 2011-2022 走看看