zoukankan      html  css  js  c++  java
  • UVALive 6491 You win! 状态DP

    这个题目上周的对抗赛的,美国2013区域赛的题目,上次比赛真惨,就做出一道题,最多的也只做出两道,当时想把这题做出来,一直TLE。

    这个题目用挂在Hunnu OJ的数据可以过,但UVALive上死活过不了,好像UVALive卡的时间不太对,没人过了这道题。

    我当初是想用一个dp[s]表示键入状态,然后由dp[0]开始逐渐向上深搜,结果就TLE了,后来比较了一下别人的代码,,果然我这样还是不行

    不管我怎么优化,我这一维数组,不能对某个状态马上就返回,因为随时可以再被更新,但是如果用个二维数组,dp[s][i],表示在状态为s的时候,键入第i个字符时候的最小键入数目,就可以只更新一次,下次再遇到这个情况就能马上return了

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 18
    #define INF 1<<30
    using namespace std;
    char ch[N];
    int len,dp[1<<N][N],ALL;
    //int up[1<<N][N];
    /*
    int abs(int a,int b)
    {
        if (a>b) return a-b;
        else  return b-a;
    }
    */
    int diff(int a, int b) //这个函数和下面的函数都是计算转换字符的按键数,结果下面那个是错的,原因是在计算从Z字母转换过去的时候,下面那个算错了,没照顾到a在b的后面的情况。为了这个BUG我检查了好久 真不应该啊
    {
        int ans=abs(a-b);
        return min(ans,'Z'-'A'-ans+1);
    }
    int ccounts(char a,char b)
    {
        int asc1=a-'A';
        int asc2=b-'A';
        int z='Z'-'A';
        int press=abs(asc1-asc2);
        press=min((press),z-asc2+1+asc1);
        return press;
    
    }
    /*
    void solve(int s,int d)
    {
        if (d==len) return;
        //if (vis[s]) return;
        vis[s]=1;
        if (dp[ALL]<=dp[s]) return;
        for (int i=0; i<len; i++)
        {
            if ((1<<i)&s) continue;
            int nt=s+(1<<i);
            int tmp;
            //cout<<"p1"<<endl;
            //if (up[s][i]==0)
             //up[s][i]=counts(i,s,ch[i]);
            tmp=dp[s]+counts(i,s,ch[i]);
            //cout<<"p2"<<endl;
            //cout<<tmp<<endl;
            if (dp[nt]>tmp)
            {
                dp[nt]=tmp;
                mouse[nt]=i+1;
                action[nt]=ch[i]-'A';
                solve(nt,d+1);
            }
            else
            if (vis[nt]==0)
             solve(nt,d+1);
            //cout<<"p3"<<endl;
            //cout<<dp[nt]<<endl;
    
    
        }
    }
    */
    int solve (int s,int last) //记忆化搜索
    {
        if (dp[s][last]) return dp[s][last];
        if (s==0) return 0;
        dp[s][last]=INF;
        int pos=0;
        for (int i=0;i<=last;i++)
        {
            if ((1<<i)&s) pos++;
        }
        for (int i=0,j=0;i<len;i++)
        {
            if ((1<<i)&s)
            {
                j++;
                if (j==pos) continue;
                int cur= j>pos? j-pos:pos-j-1;
                int rng=diff(ch[i],ch[last]);
                dp[s][last]=min(dp[s][last],1+cur+rng+solve(s^(1<<last),i));
            }
        }
        return dp[s][last];
    
    }
    int main()
    {
        //init();
        while (scanf("%s",ch))
        {
            len=strlen(ch);
            if (len==1 && ch[0]=='0') break;
            memset(dp,0,sizeof dp);
            ALL=1<<len;
            ALL--;
            for (int i=0;i<len;i++)
            {
                dp[1<<i][i]=diff('A',ch[i])+1;
            }
            int ans=INF;
            for (int i=0;i<len;i++){
               ans=min(ans,solve(ALL,i));
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    onInterceptTouchEvent 与 onTouchEvent 分析与MotionEvent在ViewGroup与View中的分发
    不用windows不会死
    iframe动态改变内嵌页面高度
    算法5-8:矩形相交
    浅析数据库连接池(二)
    Ubuntu下(Linux+Apache+MYSQL+PHP, LAMP)环境搭建
    unix环境高级编程----进程控制wait()
    centos7 通过kvm+vnc 实现远程桌面虚拟化和创建windows、Linux虚拟机
    Android native层动态库注射
    Windows10 下 JAVA JDK版本设置修改操作
  • 原文地址:https://www.cnblogs.com/kkrisen/p/3611620.html
Copyright © 2011-2022 走看看