[BZOJ1138][POI2009]Baj 最短回文路
[BZOJ1138][POI2009]Baj 最短回文路
试题描述
输入
输出
对于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 最短回文路的更多相关文章
- bzoj 1138: [POI2009]Baj 最短回文路 dp优化
1138: [POI2009]Baj 最短回文路 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 161 Solved: 48[Submit][Sta ...
- bzoj 1138: [POI2009]Baj 最短回文路
额,,貌似网上的题解都说超时之类的. 然而我这个辣鸡在做的时候不知道在想什么,连超时的都不会. 超时的大概是这样的,f[x][y]表示x到y的最短回文路,然后更新的话就是 f[x][y]更新到 f[a ...
- [Swift]LeetCode214. 最短回文串 | Shortest Palindrome
Given a string s, you are allowed to convert it to a palindrome by adding characters in front of it. ...
- [python,2019-02-15] 最短回文串
给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串.找到并返回可以用这种方式转换的最短回文串. 示例 1: 输入: "aacecaaa" 输出: "aaa ...
- leetcode 214. 最短回文串 解题报告
给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串.找到并返回可以用这种方式转换的最短回文串. 示例 1: 输入: "aacecaaa" 输出: "aaa ...
- 214 Shortest Palindrome 最短回文串
给一个字符串 S, 你可以通过在字符串前面添加字符将其转换为回文串.找到并返回可以用这种方式转换的最短回文串.例如:给出 "aacecaaa",返回 "aaacecaaa ...
- Leetcode 214.最短回文串
最短回文串 给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串.找到并返回可以用这种方式转换的最短回文串. 示例 1: 输入: "aacecaaa" 输出: &qu ...
- Java实现 LeetCode 214 最短回文串
214. 最短回文串 给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串.找到并返回可以用这种方式转换的最短回文串. 示例 1: 输入: "aacecaaa" 输出 ...
- [LeetCode] Shortest Palindrome 最短回文串
Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. ...
随机推荐
- Service官方教程(10)Bound Service的生命周期函数
Managing the Lifecycle of a Bound Service When a service is unbound from all clients, the Android sy ...
- 加密解密(3)Bob到CA申请证书过程
网络安全中最知名的人物大概就是Bob和Alice了,因为很多安全原理阐述中都用这两个虚拟人物来进行实例说明. 我们来看看Bob是怎么从CA中心获得一个数字证书的: 1.Bob首先创建他自己的密钥对(k ...
- poj2573Bridge(过桥问题)
链接 A,B为最快和次快 有两种方式可以使c,d过桥 一是a与c一起走,a回来接d再与d一起走,一直到对岸人为0为止 而是 a与b一起走 a回来送灯 c与d一起走 b回来送灯 重复此过程. 只剩2人时 ...
- 窗体WINFORM
窗体的事件:删除事件:先将事件页面里面的挂好的事件删除,再删后台代码里面的事件 Panel是一个容器 1.Label -- 文本显示工具Text:显示的文字取值.赋值:lable1.Text 2.Te ...
- 初学Ajax
AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术. AJAX = 异步 JavaScript和 ...
- 死磕 java集合之LinkedList源码分析
问题 (1)LinkedList只是一个List吗? (2)LinkedList还有其它什么特性吗? (3)LinkedList为啥经常拿出来跟ArrayList比较? (4)我为什么把LinkedL ...
- Android组件化开发(注意事项)
1.Manifest合并 在Android studio编译项目时,无论你使用了几个Module都会把所有Manifest最终合并成一个,需要我们注意的是application标签下这个几个属性引用的 ...
- 新浪qq登录
一:到腾讯QQ互联上申请APPID和APPKEY.申请地址: http://connect.qq.com/ 如同,这里我们可以获取到需要跳转到的APPID和APPKEY.新浪微博的申请同理 二:在Th ...
- C/C++ new/delete []、内存泄漏、动态数组
一.概念 new/delete是用于动态分配和撤销内存的运算符.new/delete是c++里才有的,c中是用malloc和free,c++虽然也可以用,但是不建议用.当我们使用关键字new在堆上动态 ...
- 迅为I.MX6Q开发板配不同分辨率不同尺寸液晶屏幕
I.MX6Q开发板: 核心板参数 尺寸:51mm*61mm iMX6Q四核CPU:Freescale Cortex-A9 四核 i.MX6Q,主频 1.2 GHz iMX6DL双核CPU:Freesc ...