bzoj1138
dp+spfa优化
最朴素的dp是dp[i][j]表示i->j的最短路,然后把所有pair(i,i)放到队列里跑spfa,但是这样被卡掉了,那么我们要优化一下
问题在于每次我们转移的时候要枚举i和j的邻居,这样会被两个连起来的菊花卡掉,那么我们希望一次只走一步,那么复杂度会大大降低,于是我们设一个状态g[i][j][k],表示当前在i,j,上一条出边的字符为k,这样我们让f和g交替转移,达到了每次只走一步的目标,然后就能过了,原先每次转移最坏O(m*m)?现在大概是O(n*m)的转移,状态数O(n*n*26)
#include<bits/stdc++.h>
using namespace std;
const int N = , inf = 0x3f3f3f3f;
struct edge {
int nxt, to, c;
} e[N * N << ];
struct node {
int u, v, c;
node(int u, int v, int c) : u(u), v(v), c(c) {}
};
int n, m, cnt = , q, last;
int head1[N], head2[N], f[N][N], g[N][N][], vis[N][N][];
void link1(int u, int v, int c)
{
e[++cnt].nxt = head1[u];
head1[u] = cnt;
e[cnt].to = v;
e[cnt].c = c;
}
void link2(int u, int v, int c)
{
e[++cnt].nxt = head2[u];
head2[u] = cnt;
e[cnt].to = v;
e[cnt].c = c;
}
void bfs()
{
queue<node> q;
memset(f, inf, sizeof(f));
memset(g, inf, sizeof(g));
for(int i = ; i <= n; ++i) vis[i][i][] = , f[i][i] = , q.push(node(i, i, ));
for(int i = ; i <= n; ++i)
for(int j = ; j < ; ++j) vis[i][i][j] = , g[i][i][j] = , q.push(node(i, i, j));
while(!q.empty())
{
node o = q.front();
q.pop();
int u = o.u, v = o.v;
vis[u][v][o.c] = ;
if(o.c == )
{
for(int i = head1[v]; i; i = e[i].nxt) if(g[u][e[i].to][e[i].c] > f[u][v] + )
{
g[u][e[i].to][e[i].c] = f[u][v] + ;
if(!vis[u][e[i].to][e[i].c])
{
vis[u][e[i].to][e[i].c] = ;
q.push(node(u, e[i].to, e[i].c));
}
}
}
else
{
for(int i = head2[u]; i; i = e[i].nxt) if(e[i].c == o.c && f[e[i].to][v] > g[u][v][o.c])
{
f[e[i].to][v] = g[u][v][o.c] + ;
if(!vis[e[i].to][v][])
{
vis[e[i].to][v][] = ;
q.push(node(e[i].to, v, ));
}
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = ; i <= m; ++i)
{
int u, v;
char c[];
scanf("%d%d%s", &u, &v, c);
link1(u, v, c[] - 'a');
link2(v, u, c[] - 'a');
}
bfs();
scanf("%d%d", &q, &last);
q--;
while(q--)
{
int x;
scanf("%d", &x);
printf("%d\n", f[last][x] == inf ? - : f[last][x]);
last = x;
}
return ;
}
bzoj1138的更多相关文章
- [BZOJ1138][POI2009]Baj 最短回文路
[BZOJ1138][POI2009]Baj 最短回文路 试题描述 N个点用M条有向边连接,每条边标有一个小写字母. 对于一个长度为D的顶点序列,回答每对相邻顶点Si到Si+1的最短回文路径. 如果没 ...
随机推荐
- [HDU3062]Party(2-sat)
传送门 2-sat问题,只需要判断yes或no 所以可以直接连边,缩点,判断同一组的是否在同一个块中. #include <cstdio> #include <stack> # ...
- 【01背包变形】Robberies HDU 2955
http://acm.hdu.edu.cn/showproblem.php?pid=2955 [题意] 有一个强盗要去几个银行偷盗,他既想多抢点钱,又想尽量不被抓到.已知各个银行 的金钱数和被抓的概率 ...
- 单源最短路径 Bellman_ford 和 dijkstra
首先两个算法都是常用于 求单源最短路径 关键部分就在于松弛操作 实际上就是dp的感觉 if (dist[e.to] > dist[v] + e.cost) { dist[e.to] = dist ...
- Codeforces Round #298 (Div. 2) D. Handshakes [贪心]
传送门 D. Handshakes time limit per test 1 second memory limit per test 256 megabytes input standard in ...
- CodeForces 592D Super M
先把没用的边去掉,求出包含m个点的最小树.然后求出最小树的直径就可以得到答案了. #include <cstdio> #include <cstring> #include & ...
- linux otl oracle数据库连接例子
#include <string> #include <iostream> using namespace std; #define OTL_ORA10G //我连的是LI ...
- RESTful API设计规范收集
说明:其实没有绝对的规范,达到90%即可. 理解RESTful架构:http://www.ruanyifeng.com/blog/2011/09/restful.html RESTful API 设计 ...
- Win8系统如何关闭用户账户控制UAC
按WIN+S,屏幕右侧出现搜索框,在搜索框中输入UAC,然后单击"更改用户账户控制设置" 然后把弹出的窗口改成"从不通知"就可以了
- Java入门 第一季第五章 编程练习解析
这是我学习慕课网Java课程的笔记.原视频链接为:http://www.imooc.com/learn/85 5-1 基本写法 自己主动补全快捷键:alt + / 5-2 输入输出 使用Scanner ...
- 为什么不建议用Table布局
Tables的缺点 1.Table要比其它html标记占很多其它的字节.(延迟下载时间.占用server很多其它的流量资源.) 2.Tablle会阻挡浏览器渲染引擎的渲染顺序.(会延迟页面的生成速度, ...