BZOJ 1138 POI2009 Baj 最短回文路 BFS

+题目大意:给定一张有向图,每个点有一个字符,多次求两点的最短回文路

据说这道题第一次做的人都会T?

一开始的思路是这样的:令fx,y表示从点x走到点y的最短回文路径,转移fx,y=min{fz,w+2|x?c?>z,w?c?>y}

然后广搜,果断T了= =

冗余的转移太多了……

正解是这样的:

令gx,y,c表示从点x走到点y,除了最后一条边之外是回文路径且最后一条边的字符为c的最短路

然后转移是这样的:

gx,y,c=min{fx,z+1|z?c?>y}

fx,y=min{gz,y,c+1|x?c?>z}

这样的复杂度是O(nm+26n2)的,就可以通过了

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 440
using namespace std;
struct abcd{
    int to,c,next;
}table[60600];
int head[M],tot;
int n,m;
int f[M][M],g[M][M][26];
pair<pair<int,int>,int> q[M*M*27];
int r,h;
vector<int> a[M][26];
void Add(int x,int y,int z)
{
    table[++tot].to=y;
    table[tot].c=z;
    table[tot].next=head[x];
    head[x]=tot;
}
void BFS()
{
    vector<int>::iterator it;
    int i;
    while(r!=h)
    {
        pair<pair<int,int>,int> temp=q[++h];
        int x=temp.first.first,y=temp.first.second;
        if(temp.second==-1)
        {
            for(i=head[y];i;i=table[i].next)
                if(g[x][table[i].to][table[i].c]==-1)
                    g[x][table[i].to][table[i].c]=f[x][y]+1,q[++r]=make_pair(make_pair(x,table[i].to),table[i].c);
        }
        else
        {
            for(it=a[x][temp.second].begin();it!=a[x][temp.second].end();it++)
                if(f[*it][y]==-1)
                    f[*it][y]=g[x][y][temp.second]+1,q[++r]=make_pair(make_pair(*it,y),-1);
        }
    }
}
int main()
{
    int i,x,y;
    char p[10];
    cin>>n>>m;
    memset(f,-1,sizeof f);
    memset(g,-1,sizeof g);
    for(i=1;i<=n;i++)
        f[i][i]=0,q[++r]=make_pair(make_pair(i,i),-1);
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%s",&x,&y,p+1);
        Add(x,y,p[1]-‘a‘);
        a[y][p[1]-‘a‘].push_back(x);
        if(~f[x][y]) continue;
        f[x][y]=1,q[++r]=make_pair(make_pair(x,y),-1);
    }
    BFS();
    static int a[M],d;
    cin>>d;
    for(i=1;i<=d;i++)
        scanf("%d",&a[i]);
    for(i=2;i<=d;i++)
        printf("%d\n",f[a[i-1]][a[i]]);
    return 0;
}
时间: 2024-10-18 09:58:45

BZOJ 1138 POI2009 Baj 最短回文路 BFS的相关文章

bzoj 1138: [POI2009]Baj 最短回文路 dp优化

1138: [POI2009]Baj 最短回文路 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 161  Solved: 48[Submit][Status] Description N个点用M条有向边连接,每条边标有一个小写字母. 对于一个长度为D的顶点序列,回答每对相邻顶点Si到Si+1的最短回文路径. 如果没有,输出-1. 如果有,输出最短长度以及这个字符串. Input 第一行正整数N和M ( 2 ≤ N ≤ 400 , 1 ≤ M ≤

bzoj 1138: [POI2009]Baj 最短回文路

额,,貌似网上的题解都说超时之类的. 然而我这个辣鸡在做的时候不知道在想什么,连超时的都不会. 超时的大概是这样的,f[x][y]表示x到y的最短回文路,然后更新的话就是 f[x][y]更新到 f[a][b] 当x->a,y->b且边的颜色是一样的. 然后yy了一下为什么会超时呢.... 然后想到了一个sb的情况..两个菊花图连起来...这样的复杂度就呵呵呵了..每次用f[x][y]更新的话都要枚举一个颜色,然后把另一边的颜色找出来,这样显然是要爆炸的. 为了避免这种sb情况,就引入了一个叫题

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][

[BZOJ1138][POI2009]Baj 最短回文路

试题描述 N个点用M条有向边连接,每条边标有一个小写字母. 对于一个长度为D的顶点序列,回答每对相邻顶点Si到Si+1的最短回文路径. 如果没有,输出-1. 如果有,输出最短长度以及这个字符串. 输入 第一行正整数N和M ( 2 ≤ N ≤ 400 , 1 ≤ M ≤ 60,000 ) 接下来M行描述边的起点,终点,字母.接下来D表示询问序列长度 ( 2 ≤ D ≤ 100 ) 再接下来D个1到N的整数 输出 对于D-1对相邻点,按要求输出一行.如果没合法方案,输出-1. 如果有合法,输出最短长

bzoj 2565: 最长双回文串

Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba",不相同).输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串. Input 一行由小写英文字母组成的字符串S. Output 一行一个整数,表示最长双回文子串的长度. Sample Input baacaabbacabb Sample Output 12 HINT

BZOJ 3676 【APIO2014】 回文串

题目链接:回文串 我终于也会回文自动机辣! 其实吗--我觉得回文自动机(听说这玩意儿叫\(PAM\))还是比较\(simple\)的--至少比\(SAM\)友善多了-- 所谓回文自动机,每个节点就代表一个回文串.回文自动机的每个节点有两个东西,一个是\(next\),一个是\(fail\).\(next_{u,x}\)指向节点\(u\)所代表的回文串在两端各添加一个字符\(x\)得到一个新的回文串.\(fail_u\)则指向\(u\)这个节点的最长后缀回文串(不包括本身).当然还有一个\(len

BZOJ 2565 最长双回文串 Hash+二分

题目大意:给定一个字符串,求一个最长的子串,该字串可以分解为两个回文子串 傻逼的我又忘了Manacher怎么写了= = 无奈Hash+二分吧 首先将字符串用分隔符倍增,然后求出以每个点为中心的最长回文半径 然后考虑两个回文串怎么合并成一个 我们发现图中以i为中心的回文串和以j为中心的回文串合并后长度恰好为(j-i)*2 能合并的前提是以两个点为中心的回文串有交点 那么对于每个j我们要求出有交点的最左侧的i 维护一个后缀min随便搞搞就可以了 #include <cstdio> #include

[BZOJ]4755: [Jsoi2016]扭动的回文串

Time Limit: 10 Sec  Memory Limit: 512 MB Description JYY有两个长度均为N的字符串A和B. 一个"扭动字符串S(i,j,k)由A中的第i个字符到第j个字符组成的子串与B中的第j个字符到第k个字符组成的子串拼接而成. 比如,若A='XYZ',B='UVW',则扭动字符串S(1,2,3)='XYVW'. JYY定义一个"扭动的回文串"为如下情况中的一个: 1.A中的一个回文串: 2.B中的一个回文串: 3.或者某一个回文的扭动

回文树或者回文自动机,及相关例题

回文树简述 在大部分说法中,回文树与回文自动机指的是一个东西: 回文树是对一个字符串,基于自动机思想构建的处理回文问题的树形结构: 回文树是对着一个单串建立的: 于是他主要用于计数(回文子串种类及个数) 基本建立思路是先建立其前缀的回文树,然后每加上一个字符,统计影响: 回文树存在fail指针但一般不承接字符串匹配问题: (回文树大概可以判定一个回文串是不是一个串的子串,但KMP之类的可以做得更好) 构建好的回文树,是这样的: (好难看) 可看出: 存在两个树结构,分别记录奇数|偶数长度的回文: