1138: [POI2009]Baj 最短回文路

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 161  Solved: 48
[Submit][Status]

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

  一看题,这不是水dp么?设dp[i][j]为i到j的回文最短路长度,随便转移一下就行了,写出来才发现TLE的一塌糊涂。在一系列常数优化后直接在网上找题解了。。。

  优化0:这算不上什么优化吧,由于每次只枚举特定起点特定颜色的边,用前向星比枚举边要快一些。

  优化1:这个for是不是嵌套的太多了,冗余状态很多,用类似于spfa的方法优化一下。

  优化2:直觉时卡时间的点应该有很多重边,先将边去重。

  优化3:是不是觉得我们在dp[i][j]向下转移的过程中分别从起点终点枚举边很慢,我们外加一个数组dp2[i][j][k]表示从i到j经过一条边权为k的边和一个回文串的最短距离,每次转移变为了dp与dp2的相互更新,很不幸的一点是仔细想一想这样并不能优化时间复杂度级别,但是是一个很强劲的剪枝。

  

  网上的题解称光优化3就能过,本人太弱,用了优化3还是T,就把优化1,2,3都加上了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 450
#define MAXM 61000
#define INF 0x3f3f3f3f
struct edge
{
int s,t,c;
}e[MAXM],e2[MAXM];
bool cmp_edge(edge e1,edge e2)
{
if (e1.s!=e2.s)return e1.s<e2.s;
if (e1.c!=e2.c)return e1.c<e2.c;
if (e1.t!=e2.t)return e1.t<e2.t;
return false;
}
bool cmp_edge2(edge e1,edge e2)
{
if (e1.t!=e2.t)return e1.t<e2.t;
if (e1.c!=e2.c)return e1.c<e2.c;
if (e1.s!=e2.s)return e1.s<e2.s;
return false;
}
bool operator ==(edge e1,edge e2)
{
return e1.s==e2.s && e1.t==e2.t && e1.c==e2.c;
}
int head[MAXN*],head2[MAXN*];
int dp[MAXN][MAXN],dp2[MAXN][MAXN][];
inline bool deal(int &x,int y)
{
if (x>y)
{
x=y;
return true;
}else
return false;
}
pair<int,int> q[];
bool vis[MAXN][MAXN];
int main()
{
freopen("input.txt","r",stdin);
int i,j,k,x,y,z,n,m,a,b;
scanf("%d%d\n",&n,&m);
char ch;
for (i=;i<m;i++)
{
scanf("%d%d %c\n",&x,&y,&ch);
e[i].s=x;
e[i].t=y;
e[i].c=ch-'a';
e2[i]=e[i];
}
sort(e,e+m,cmp_edge);
sort(e2,e2+m,cmp_edge2);
x=m;
m=unique(e,e+x)-e;
m=unique(e2,e2+x)-e2;
for (i=;i<m;i++)
{
head[e[i].s*+e[i].c]++;
head2[e[i].t*+e[i].c]++;
}
for (i=;i<=n*+;i++)
head[i]+=head[i-],head2[i]+=head2[i-];
for (i=n*+;i>=;i--)
head[i]=head[i-],head2[i]=head2[i-];
head[]=;head2[]=;
e[m].s=e2[m].t=INF; memset(dp,INF,sizeof(dp));
memset(dp2,INF,sizeof(dp2));
for (i=;i<=n;i++)
dp[i][i]=;
for (i=;i<m;i++)
dp[e[i].s][e[i].t]=;
int h=-,t=-;
for (i=;i<=n;i++)
for (j=;j<=n;j++)
if (dp[i][j]!=INF)
q[++t]=make_pair(i,j),vis[i][j]=true;; while (h<t)
{
x=q[++h].first;
y=q[h].second;
vis[x][y]=false;
for (a=head2[x*+k];e2[a].t==x;a++)
{
if (dp2[e2[a].s][y][e2[a].c]>dp[x][y]+)
{
dp2[e2[a].s][y][e2[a].c]=dp[x][y]+;
if (!vis[e2[a].s][y])
{
vis[e2[a].s][y]=true;
q[++t]=make_pair(e2[a].s,y);
}
}
}
for (b=head[y*+k];e[b].s==y;b++)
{
if (dp[x][e[b].t]>dp2[x][y][e[b].c]+)
{
dp[x][e[b].t]=dp2[x][y][e[b].c]+;
if (!vis[x][e[b].t])
{
vis[x][e[b].t]=true;
q[++t]=make_pair(x,e[b].t);
}
}
}
}
int q;
scanf("%d",&q);
scanf("%d",&x);
for (i=;i<q;i++)
{
scanf("%d",&y);
if (dp[x][y]==INF)
{
printf("%d\n",-);
}else
{
printf("%d\n",dp[x][y]);
}
x=y;
}
}

bzoj 1138: [POI2009]Baj 最短回文路 dp优化的更多相关文章

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

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

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

    [BZOJ1138][POI2009]Baj 最短回文路 试题描述 N个点用M条有向边连接,每条边标有一个小写字母. 对于一个长度为D的顶点序列,回答每对相邻顶点Si到Si+1的最短回文路径. 如果没 ...

  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. bzoj2084/luoguP3501 [Poi2010]Antisymmetry(回文自动机+dp)

    bzoj2084/luoguP3501 [Poi2010]Antisymmetry(回文自动机+dp) bzoj Luogu 对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一 ...

随机推荐

  1. 自定义ContentProvider

    ContentProvider作为安卓的四大组件之一,在看开发中用到的频率远不如其他三个,以至于我都把这个东西给忘了,最近由于工作原因,不得不重新拾起来总结一下,那么今天就来说说自定义ContentP ...

  2. Android_常用控件及适配器

    TextView 控件中显示的内容必须是文本 TextView中常用的属性 android:text TextView中显示的文本内容 android:textColor 字体颜色 格式为#RGB # ...

  3. 利用java开发一个双击执行的小程序

    之前我们利用java写了很多东西,但是好像都没有什么实际意义. 因为有意义桌面小程序怎么都得有个界面,可是界面又不太好搞.或者 了解到这一层的人就少之又少了. 呀,是不是还得开辟一些版面来介绍awt和 ...

  4. JavaScript入门(7)

    一.什么是函数 函数:把完成特定功能的代码放到一个函数里,直接调用这个函数,就省去重复输入大量代码的麻烦 函数的作用:写一次代码,然后反复地重用这个代码 Eg: 求多组数的和,不使用函数 { var ...

  5. C# 日期转换函数

    string.Format("{0:d}",dt);//2005-11-5 string.Format("{0:D}",dt);//2005年11月5日 str ...

  6. mongodb write 【摘自网上,只为记录,学习】

    mongodb有一个write concern的设置,作用是保障write operation的可靠性.一般是在client driver里设置的,和db.getLastError()方法关系很大 一 ...

  7. UVA 11300 Spreading the Wealth (数学推导 中位数)

    Spreading the Wealth Problem A Communist regime is trying to redistribute wealth in a village. They ...

  8. 文件打开方式O_DSYNC、O_RSYNC、O_SYNC

    O_DSYNC: 每次write都等待物理I/O完成,但是如果写操作不影响读取刚写入的数据,则不等待文件属性更新 O_RSYNC: 每个以文件描述符作为参数的read操作等待,直到所有对文件同一部分的 ...

  9. shell中的双引号,单引号,反引号

    在shell中引号分为三种:单引号,双引号和反引号. 单引号 ‘ 由单引号括起来的字符都作为普通字符出现.特殊字符用单引号括起来以后,也会失去原有意义,而只作为普通字符解释.单引号用于保持引号内所有字 ...

  10. jQuery学习教程(2)

    由于一件事情打断了我的生活节奏,每天都学习都在托托拉拉,导致很多进度都没有达到自己预期的效果 在上一个章节我学到了环境的搭建,以及对jquery的熟悉.现在开始对其具体进行熟悉了. 一.如何使用选择器 ...