tyvj P1179 飘飘乎居士数列游戏

来源:互联网 发布:c#用什么软件编程 编辑:程序博客网 时间:2024/05/01 07:06

来自本人百度空间 2010-10-24 19:17

帮zhanglunAC一题绿的,,然后自己卡了个第10,,庆祝一下。。
感谢CCTV,MTV,连云港TV。。。。。
最后还要感谢飘飘大神指导。。。。。

这题框架是动规,,
递推关系:dp[i]=max{dp[j]}+1 (第j个数变化一个数可以变为第i个数)
如果直接做的话,我是60分。其他TLE。。

大神指导:用前缀树优化,
前缀树就是字典序。。查找的确方便了很多。。。
一遍动规一遍去建树,然后枚举变化情况,并找出离当前数字最近的数字
递推方程也要稍微改一下下标。。 总体上不是非常复杂的

#include<fstream>
using namespace std;
ifstream fin("P1179.in");
ofstream fout("P1179.out");

int n,m,ans=0,len=0;//len是等会建树时标记位置的 
int mat[20001][11];//mat是存数的 
int tree[200000][10],dp[1000000];//借鉴了飘飘的tree,这是存数的。dp是动规的

int main()
{
    int fix(int n);
    int find(int n,int l,int k);
    fin>>n>>m;
    char k;
    for (int i=1;i<=n;i++)//把数字弄进数组 
        for (int j=1;j<=m;j++)
        {
            fin>>k;
            mat[i][j]=int(k)-int('0');
        }
        
    int node;
    for (int j=1;j<=n;j++)
    {
        node=fix(j);//把这个数放进树中 
        for (int i=1;i<=m;i++)//枚举变化情况 
            for (int k=0;k<=9;k++)
            {
                if (k==mat[j][i]) continue;//如果没有变就继续 
                int pre=find(j,i,k);//找到离第i个数最近的跟变化情况一样的数,如果没有的话,返回0 
                dp[node]=max(dp[node],dp[pre]+1);//动规 
            }    
        ans=max(ans,dp[node]);//维护ans 
    }    
    
    fout<<ans<<endl;
    
    return 0;
}

int fix(int n)//这个把第n个数按进树的函数 
{
    int p=0;
    for (int i=1;i<=m;i++)
    {
        if (tree[p][mat[n][i]]==0)//找到第p个节点,如果这个节点下面没有我们要的数就新加一个节点 
        {
            len++;
            tree[p][mat[n][i]]=len;
        }   
        p=tree[p][mat[n][i]];//进入下一个节点继续查找 
    }
    return p;//返回最终的位置 
}   

int find(int n,int l,int k)//这是找第n个数在树种位置的函数 
{
    int p=0,b[11];
    for (int i=1;i<=m;i++)    b[i]=mat[n][i];
    b[l]=k;//把变化过后的数放进b数组 
    for (int i=1;i<=m;i++)
    {
        if (tree[p][b[i]]==0)   return 0;//如果压根儿就没这数,,返回0; 
        p=tree[p][b[i]];//向下找节点 
    }   
    return p;//返回最终的位置 
}  


原创粉丝点击