来自本人百度空间 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;//返回最终的位置
}