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

题意:链接略

方法: 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 30
using 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");
    }
}

你可能感兴趣的:(优化,dp,poi,2009)