[BZOJ 1138] POI2009 Baj 最短回文路

来源:互联网 发布:阿里金融云 编辑:程序博客网 时间:2024/05/20 11:26

做题的过程还是挺曲折的。

最下的想法是每次询问的时候把每两个点打包成新的起点,跑最短路,知道走到相同的点上或者走到一条边的两边。

然后就毫无压力的T了。。。。哭

后来在同学的提醒下,反过来思考。将相同的点 和 同一条边上的两个点 做起点,预处理每一个状态的答案,然后直接输出即可。

还是T了一点。。。。各种卡常数。。。。还是没过。。。。大哭

看题解,标算只是将原来的状态在拓展一下,这样可以降低转移的复杂度。

因为原来是这样转移的的d[i][j]=d[k][l]+2|存在边(i,k)(l,j)且两条边上的字母相同。之后状态记作d[i][j][0-25],表示i到j的路上出了开头多了一个字母,其余为回文串的最短路径。转移d[i][j][x]=d[k][j][26]+1|存在边(i,k,x),0<=x<26.   d[i][j][26]=d[i][k][x]+1|存在边(k,j,x)

这样虽然状态数增多了,但是有用状态很少,而且转移复杂度大大减小,ac无压力了生气

这道题目告诉了我可以从平衡状态数和转移复杂度上优化算法,从而减少计算量。

贴上代码

#include <cstdio>#include <vector>#include <cstring>#include <algorithm>using namespace std;#define num(x,y,k) (((x)-1)*n*27+((y)-1)*27+(k)+1)char ch;int flag[405][405],p[4320005],q[4320005],d[4320005],R[4320005];int n,m,x,y,z,i,j,k,xx,yy,ans,N,l,r;vector <int> a[405][26],b[405][26];void print(int x){  /*  int i=(x-1)/(n*27)+1;  int j=(x-1)%(n*27)/27+1;  int k=(x-1)%(n*27)%27;  if (d[x]==0) return;  if (d[x]==1){  printf("%c",flag[i][j]);  return;  }  int kk=(p[x]-1)%(n*27)%27;  printf("%c",kk+'a');  print(p[p[x]]);  printf("%c",kk+'a');*/  for (R[l=1]=x;d[ R[l] ]>1;l++)  R[l+1]=p[ p[R[l]] ];  for (int i=l;i>0;i--){  if (d[ R[i] ]<2) continue;  int k=(p[R[i]]-1)%(n*27)%27;  printf("%c",k+'a');  }    if (d[R[l]]==1){  int i=(R[l]-1)/(n*27)+1;    int j=(R[l]-1)%(n*27)/27+1;    printf("%c",flag[i][j]);  }    for (int i=1;i<=l;i++){  if (d[ R[i] ]<2) continue;  int k=(p[R[i]]-1)%(n*27)%27;  printf("%c",k+'a');  }}int main(){  scanf("%d%d",&n,&m);  for (i=1;i<=m;i++){  scanf("%d %d %c\n",&x,&y,&ch);  a[x][ch-'a'].push_back(y);  b[y][ch-'a'].push_back(x);  flag[x][y]=ch;  }  memset(d,127/2,sizeof(d));  for (i=1,r=0;i<=n;i++)    d[ q[++r]=num(i,i,26) ]=0;  for (i=1;i<=n;i++)  for (j=1;j<=n;j++)  if (i!=j&&flag[i][j]) d[ q[++r]=num(i,j,26) ]=1;    int len;  for (l=1;l<=r;l++){  x=(q[l]-1)/(n*27)+1;  y=(q[l]-1)%(n*27)/27+1;  z=(q[l]-1)%(n*27)%27;  if (z==26){    for (i=0;i<26;i++){      len=b[x][i].size();      for (j=0;j<len;j++)      if (d[ num(b[x][i][j],y,i) ]>d[ q[l] ]+1){        d[ q[++r]=num(b[x][i][j],y,i) ]=d[ q[l] ]+1;        p[ q[r] ]=q[l];      }      }  } else  {    len=a[y][z].size();    for (j=0;j<len;j++)    if (d[ num(x,a[y][z][j],26) ]>d[ q[l] ]+1){       d[ q[++r]=num(x,a[y][z][j],26) ]=d[ q[l] ]+1;      p[ q[r] ]=q[l];    }   }  }    for (i=1;i<=n*n*27;i++)    if (d[i]==d[0]) d[i]=-1;  scanf("%d",&m);  scanf("%d",&x); m--;  while (m--){  scanf("%d",&y);  printf("%d",d[num(x,y,26)]);  if (d[num(x,y,26)]!=-1)  {    printf(" ");    print(num(x,y,26));  }  printf("\n");  x=y;  }    return 0;}


0 0
原创粉丝点击