bzoj1138 [POI2009]Baj 最短回文路 DP+宽搜

来源:互联网 发布:windows日志查询 编辑:程序博客网 时间:2024/06/06 10:04

POI就算是很老的题目也很锻炼思维啊。。。

Description

N个点用M条有向边连接,每条边标有一个小写字母。 对于一个长度为D的顶点序列,回答每对相邻顶点Si到Si+1的最短回文路径。 如果没有,输出-1。 如果有,输出最短长度以及这个字符串。

Input

第一行正整数N和M ( 2 ≤ N ≤ 400 , 1 ≤ M ≤ 60,000 ) 接下来M行描述边的起点,终点,字母。接下来D表示询问序列长度 ( 2 ≤ D ≤ 100 ) 再接下来D个1到N的整数

Output

对于D-1对相邻点,按要求输出一行。如果没合法方案,输出-1。 如果有合法,输出最短长度

Sample Input

6 7

1 2 a

1 3 x

1 4 b

2 6 l

3 5 y

4 5 z

6 5 a

3

1 5 3
Sample Output

3

-1

题意很好理解就不说了
比较容易想到枚举中间点向两边扩展,或者对于询问序列,枚举中间点,思想差不多,反正都会T。
设f[i][j]表示从i到j的最短回文路,g[i][j][k]表示从i到j的最短回文路再加上一个字符k(最后一条边不回文)。
那么我们可以用g[i][j][k]更新f[i][j],也可以反过来更新。具体来说:
f[i][j]=g[k][j][c]+1(edge[i][k]=c)
然后反过来更新。
g[i][j][k]=f[i][v]+1(edge[v][j]=k)
具体实现的话可能硬来不是很好,注意一下模拟链表的实现,这种trick能在关键时候给予帮助,不能小觑。

#include<cstdio>#include<algorithm>#include<cstring>#include<queue>#define mp make_pair#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=2e5+5;const int inf=0x3f3f3f3f;int n,m,tot;int head[N][27],next[N],go[N],a[N],head1[N][27];int f[405][405];int g[405][405][27];char c[N];queue<pair<int,pair<int,int> > > q;inline void add(int x,int y,int z){    go[++tot]=y;next[tot]=head[x][z];head[x][z]=tot;    go[++tot]=x;next[tot]=head1[y][z];head1[y][z]=tot;}inline void bfs(){    memset(f,inf,sizeof(f));    memset(g,inf,sizeof(g));    fo(i,1,n)    f[i][i]=0,q.push(mp(i,mp(i,26)));    fo(i,1,n)    fo(j,0,25)    g[i][i][j]=0,q.push(mp(i,mp(i,j)));    while (!q.empty())    {        pair<int,pair<int,int> >u=q.front();        q.pop();        int x=u.first,y=u.second.first,z=u.second.second;        if (z==26)        {            fo(i,0,25)            for(int j=head[y][i];j;j=next[j])            {                int v=go[j];                if (f[x][y]+1<g[x][v][i])                {                    g[x][v][i]=f[x][y]+1;                    q.push(mp(x,mp(v,i)));                }            }        }        else        {            for(int i=head1[x][z];i;i=next[i])            {                int v=go[i];                if (g[x][y][z]+1<f[v][y])                {                    f[v][y]=g[x][y][z]+1;                    q.push(mp(v,mp(y,26)));                }            }        }    }}int main(){    scanf("%d%d",&n,&m);    fo(i,1,m)    {        int x,y;        char s[2];        scanf("%d%d%s",&x,&y,&s);        f[x][y]=1;        add(x,y,s[0]-'a');    }    bfs();    int q,last;    scanf("%d%d",&q,&last);    q--;    while (q--)    {        int x;        scanf("%d",&x);        printf("%d\n",f[last][x]==inf?-1:f[last][x]);        last=x;    }    return 0;}