BZOJ 1138 [POI2009]Baj 最短回文路 DP

来源:互联网 发布:女友 单机游戏 知乎 编辑:程序博客网 时间:2024/05/29 11:53

题意:链接略

方法: DP

解析:

显然我们可以找回文中点然后宽搜向两边拓展。

不过这样的复杂度的话…

枚举中点再拓展,岂不有点爆炸?

所以我们换个方式来优化。

我们设F[i][j]表示由i到j的最短回文路径长度。

设G[i][j][k]表示从i到j走一条回文路径再走一个小写字母k的最短回文路径长度。

有了这个辅助式子,问题就变得简单多了。

所有的状态最多也就n^2*k个。

直接上宽搜即可。

F[i][j]=min{G[z][j][k]+1&&edge[i][z]==k}

G[i][j][k]=min{F[i][w]+1&&edge[w][j]==k}

代码:

#include<queue>#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#define N 440#define M 60100#define K 30using namespace std;int n,m;int l,r;int map[N][N];int f[N][N];int g[N][N][K];int head[N],head2[N];int cnt;struct node{    int from,to,next;}edge[M<<1];struct element{    int from,to,alpha;}q[N*N*K];void init(){    memset(head,-1,sizeof(head));    memset(head2,-1,sizeof(head2));    cnt=1;}void edgeadd(int from,int to){    edge[cnt].from=from,edge[cnt].to=to;    edge[cnt].next=head[from];    head[from]=cnt++;    edge[cnt].from=to,edge[cnt].to=from;    edge[cnt].next=head2[to];    head2[to]=cnt++;}void bfs(){    while(l!=r+1)    {        element u=q[l++];        int x=u.from,y=u.to,alpha=u.alpha;        if(!u.alpha)        {            for(int i=head[y];i!=-1;i=edge[i].next)            {                int w=edge[i].to;                if(f[x][y]+1<g[x][w][map[y][w]])                {                    g[x][w][map[y][w]]=f[x][y]+1;                    q[++r]=(element){x,w,map[y][w]};                }            }        }else        {            for(int i=head2[x];i!=-1;i=edge[i].next)            {                int w=edge[i].to;                if(g[x][y][map[w][x]]+1<f[w][y])                {                    f[w][y]=g[x][y][map[w][x]]+1;                    q[++r]=(element){w,y,0};                }            }        }    }}int s[N];int main(){    l=1,r=0;    scanf("%d%d",&n,&m);    init();    memset(f,0x3f,sizeof(f));    memset(g,0x3f,sizeof(g));    for(int i=1;i<=m;i++)    {        int x,y;        char tmp[2];        scanf("%d%d",&x,&y);        scanf("%s",tmp);        map[x][y]=tmp[0]-'a'+1;        edgeadd(x,y);        f[x][y]=1;         q[++r]=(element){x,y,0};    }    for(int i=1;i<=n;i++)f[i][i]=0,q[++r]=(element){i,i,0};    bfs();    int d;    scanf("%d",&d);    for(int i=1;i<=d;i++)scanf("%d",&s[i]);    for(int i=2;i<=d;i++)    {        if(f[s[i-1]][s[i]]!=0x3f3f3f3f)            printf("%d\n",f[s[i-1]][s[i]]);        else puts("-1");    }}
0 0
原创粉丝点击