[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。 如果有合法,输出最短长度

输入示例

  a
x
b
l
y
z
a

输出示例

-

数据规模及约定

见“输入

题解

朴素的 dp 是这样的:设 f[i][j] 表示节点 i 到节点 j 的最短回文长度,转移的时候枚举字母 x,设节点 j 沿着带有字母 x 的边走一格所能到达的点集为集合 A,设 i 逆着带有字母 x 的边走一格所能达到的点集为集合 B。那么对于 ∀a ∈ A, ∀b ∈ B,就可以更新 f[a][b] 了,即 f[a][b] = min{ f[a][b], f[i][j] + 2 }。

但是我们发现这个算法被爆菊了。。。就是如果有很多条相同字母的边指向 i,相同字母的边从 j 出发,转移就会被卡成 O(n2) 的了。。。

解决方式就是添加一个中间状态 g[i][j][c],表示节点 i 到节点 j 的路径最后一个字母是 c,并且除掉最后一个字母后它就是一个回文路径,在这样的情况下的最短长度。那么对于状态 f[i][j],可以用节点 j 沿着字母 c(枚举)走一格到达的所有节点 b 来更新 g[i][b][c];对于状态 g[i][b][c],可以用节点 i 逆着字母 c(这个字母是固定的,即状态中的字母)走一格到达的所有节点 a 来更新 f[a][b],这样状态数变成了原来的 27 倍,转移复杂度变成了 O(n)。

转移顺序比较乱,可以用 BFS 帮助转移。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <queue>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 410
#define maxa 26
#define maxm 10660 bool G[maxn][maxn][maxa];
int f[maxn][maxn], g[maxn][maxn][maxa];
vector <int> from[maxn][maxa], to[maxn][maxa];
void AddEdge(int a, int b, int c) {
to[a][c].push_back(b);
from[b][c].push_back(a);
return ;
} struct Pair {
int a, b, c;
Pair() {}
Pair(int _1, int _2, int _3): a(_1), b(_2), c(_3) {}
};
queue <Pair> Q; int main() {
int n = read(), m = read();
for(int i = 1; i <= m; i++) {
int a = read(), b = read(); char ch[2]; scanf("%s", ch);
G[a][b][ch[0]-'a'] = 1;
} memset(f, -1, sizeof(f)); memset(g, -1, sizeof(g));
for(int i = 1; i <= n; i++) Q.push(Pair(i, i, -1)), f[i][i] = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++) if(i != j) {
bool fl = 0;
for(int c = 0; c < maxa; c++) if(G[i][j][c]) {
AddEdge(i, j, c);
fl = 1; break;
}
if(fl) f[i][j] = 1, Q.push(Pair(i, j, -1));
}
while(!Q.empty()) {
Pair u = Q.front(); Q.pop();
int a = u.a, b = u.b, c = u.c, tmp = c < 0 ? f[a][b] : g[a][b][c];
// printf("(%d, %d, %d)\n", a, b, c);
if(c < 0)
for(c = 0; c < maxa; c++)
for(int i = 0; i < to[b][c].size(); i++) {
int B = to[b][c][i];
if(g[a][B][c] < 0) g[a][B][c] = tmp + 1, Q.push(Pair(a, B, c));
}
else
for(int i = 0; i < from[a][c].size(); i++) {
int A = from[a][c][i];
if(f[A][b] < 0) f[A][b] = tmp + 1, Q.push(Pair(A, b, -1));
}
} int q = read(), st = read();
for(int i = 2; i <= q; i++) {
int u = read();
printf("%d\n", f[st][u]);
st = u;
} return 0;
}

[BZOJ1138][POI2009]Baj 最短回文路的更多相关文章

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

    1138: [POI2009]Baj 最短回文路 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 161  Solved: 48[Submit][Sta ...

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

    额,,貌似网上的题解都说超时之类的. 然而我这个辣鸡在做的时候不知道在想什么,连超时的都不会. 超时的大概是这样的,f[x][y]表示x到y的最短回文路,然后更新的话就是 f[x][y]更新到 f[a ...

  3. [Swift]LeetCode214. 最短回文串 | Shortest Palindrome

    Given a string s, you are allowed to convert it to a palindrome by adding characters in front of it. ...

  4. [python,2019-02-15] 最短回文串

    给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串.找到并返回可以用这种方式转换的最短回文串. 示例 1: 输入: "aacecaaa" 输出: "aaa ...

  5. leetcode 214. 最短回文串 解题报告

    给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串.找到并返回可以用这种方式转换的最短回文串. 示例 1: 输入: "aacecaaa" 输出: "aaa ...

  6. 214 Shortest Palindrome 最短回文串

    给一个字符串 S, 你可以通过在字符串前面添加字符将其转换为回文串.找到并返回可以用这种方式转换的最短回文串.例如:给出 "aacecaaa",返回 "aaacecaaa ...

  7. Leetcode 214.最短回文串

    最短回文串 给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串.找到并返回可以用这种方式转换的最短回文串. 示例 1: 输入: "aacecaaa" 输出: &qu ...

  8. Java实现 LeetCode 214 最短回文串

    214. 最短回文串 给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串.找到并返回可以用这种方式转换的最短回文串. 示例 1: 输入: "aacecaaa" 输出 ...

  9. [LeetCode] Shortest Palindrome 最短回文串

    Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. ...

随机推荐

  1. AJPFX关于数组获取最值的思路和方法

    思路分析:1.定义一个变量(max,初始值一般为数组中的第一个元素值),用来记录最大值.2.遍历数组,获取数组中的每一个元素,然后依次和max进行比较.如果当前遍历到的元素比max大,就把当前元素值给 ...

  2. Discrete Logging

    Discrete Logging Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5865   Accepted: 2618 ...

  3. Struts2------拦截器和标签库和注解开发

    一.解析Struts2源码中拦截器的执行 客户端请求Action,执行前端控制器,在前端控制器内部创建了Action的代理类,调用代理类的execute方法,在execute方法内部执行ActionI ...

  4. DeltaFish 选题报告总结

    选题结果:校园物资流动系统 报告地点:3A101 会议时间:16:00 ~ 18:00 与会人员:软工小组全体成员 请假人员:无  缺席人员:无 报告人:陈志锴 一.报告内容总结 1.产品功能 针对校 ...

  5. Python界面编程之六----布局

    布局(转载于–学点编程吧)通过实践可知采用了布局之后能够让我们的程序在使用上更加美观,不会随着窗体的大小发生改变而改变,符合我们的使用习惯. 绝对位置程序员以像素为单位指定每个小部件的位置和大小. 当 ...

  6. cksum - 一个文件的检查和以及字节数

    SYNOPSIS(总览) ../src/cksum [OPTION]... [FILE]... DESCRIPTION(描述) 输出CRC(循环冗余校验码)检查和以及每个FILE的字节数. --hel ...

  7. vsphere中的linux虚拟机安装vmware-tools

    先在vcenter中选中虚拟机点击安装这个工具,如图 然后这台linux虚拟机的控制台操作,挂载先建立挂载目录 cd /mnt #在挂载建一个用来挂载的文件. mkdir cdrom 使用mount命 ...

  8. 第3节 mapreduce高级:4、倒排索引的建立

    倒排索引建立 需求分析 需求:有大量的文本(文档.网页),需要建立搜索索引 最终实现的结果就是哪个单词在哪个文章当中出现了多少次 思路分析: 首选将文档的内容全部读取出来,加上文档的名字作为key,文 ...

  9. kafka 服务端消费者和生产者的配置

    在kafka的安装目录下,config目录下有个名字叫做producer.properties的配置文件 #指定kafka节点列表,用于获取metadata,不必全部指定 #需要kafka的服务器地址 ...

  10. 启发式合并CSU - 1811

    F - Tree Intersection CSU - 1811 Bobo has a tree with n vertices numbered by 1,2,…,n and (n-1) edges ...