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情况,就引入了一个叫题解的神奇的东西。

题解多设了一个东西,g[x][y][col]表示x到y且除了和y相连的那条颜色为col的边之外是回文最短路的长度。

然后有了g,就可以在一遍更新过g,f在另一边直接拿来用了。神奇2333

 1 #include<iostream>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstdio>
 5 #include<cstring>
 6 #define inf 0x3f3f3f3f
 7 using namespace std;
 8
 9 const int maxn=100005;
10 const int QWQ=505;
11
12 struct edge{
13     int to,from,next;
14 }e[maxn<<1],E[maxn<<1];
15 int head[QWQ],cnt,HEAD[QWQ],CNT;
16 void insert(int x, int y)
17 {
18     e[++cnt].next=head[x]; e[cnt].to=y; e[cnt].from=x; head[x]=cnt;
19     E[++CNT].next=HEAD[y]; E[CNT].to=x; E[CNT].from=y; HEAD[y]=CNT;
20 }
21
22 int l,r=1;
23 int n,m,map[QWQ][QWQ],f[QWQ][QWQ],g[QWQ][QWQ][30];
24 struct node{
25     int from,to,col;
26 }q[QWQ*QWQ*30];
27 void bfs()
28 {
29     while (l<r)
30     {
31         node u=q[l++];
32         int x=u.from,y=u.to;
33         if (!u.col)
34         {
35             for (int i=head[y];i;i=e[i].next)
36             {
37                 if (f[x][y]+1<g[x][e[i].to][map[y][e[i].to]])
38                 {
39                     g[x][e[i].to][map[y][e[i].to]]=f[x][y]+1;
40                     q[r++]=(node){x,e[i].to,map[y][e[i].to]};
41                 }
42             }
43         }
44         else
45         {
46             for (int i=HEAD[x];i;i=E[i].next)
47             {
48                 if (g[x][y][map[E[i].to][x]]+1<f[E[i].to][y])
49                 {
50                     f[E[i].to][y]=g[x][y][map[E[i].to][x]]+1;
51                     q[r++]=(node){E[i].to,y,0};
52                 }
53             }
54         }
55     }
56 }
57 int main()
58 {
59     scanf("%d%d",&n,&m);
60     memset(f,0x3f,sizeof(f)); memset(g,0x3f,sizeof(g));
61     for (int i=1; i<=m; i++)
62     {
63         int x,y; char Orz[2];
64         scanf("%d%d%s",&x,&y,Orz);
65         insert(x,y);
66         map[x][y]=Orz[0]-‘a‘+1;
67         f[x][y]=1;
68         q[r++]=(node){x,y,0};
69     }
70     for (int i=1; i<=n; i++) f[i][i]=0,q[r++]=(node){i,i,0};
71     bfs();
72     int T; scanf("%d",&T);
73     int x,y; scanf("%d",&x);
74     for (int i=2; i<=T; i++)
75     {
76         scanf("%d",&y);
77         if (f[x][y]!=inf) cout<<f[x][y]<<endl;
78             else puts("-1");
79         x=y;
80     }
81     return 0;
82 }
时间: 2024-11-08 10:10:02

bzoj 1138: [POI2009]Baj 最短回文路的相关文章

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 最短回文路 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,

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之类的可以做得更好) 构建好的回文树,是这样的: (好难看) 可看出: 存在两个树结构,分别记录奇数|偶数长度的回文: