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 = 410, inf = 0x3f3f3f3f;
struct edge {
    int nxt, to, c;
} e[N * N << 1];
struct node {
    int u, v, c;
    node(int u, int v, int c) : u(u), v(v), c(c) {}
};
int n, m, cnt = 1, q, last;
int head1[N], head2[N], f[N][N], g[N][N][27], vis[N][N][27];
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 = 1; i <= n; ++i) vis[i][i][26] = 1, f[i][i] = 0, q.push(node(i, i, 26));
    for(int i = 1; i <= n; ++i)
        for(int j = 0; j < 26; ++j) vis[i][i][j] = 1, g[i][i][j] = 0, 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] = 0;
        if(o.c == 26)
        {
            for(int i = head1[v]; i; i = e[i].nxt) if(g[u][e[i].to][e[i].c] > f[u][v] + 1)
            {
                g[u][e[i].to][e[i].c] = f[u][v] + 1;
                if(!vis[u][e[i].to][e[i].c])
                {
                    vis[u][e[i].to][e[i].c] = 1;
                    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] + 1;
                if(!vis[e[i].to][v][26])
                {
                    vis[e[i].to][v][26] = 1;
                    q.push(node(e[i].to, v, 26));
                }
            }
        }
    }   
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; ++i)
    {
        int u, v;
        char c[2];
        scanf("%d%d%s", &u, &v, c);
        link1(u, v, c[0] - 'a');
        link2(v, u, c[0] - 'a');
    }
    bfs();
    scanf("%d%d", &q, &last);
    q--;
    while(q--)
    {
        int x;
        scanf("%d", &x);
        printf("%d\n", f[last][x] == inf ? -1 : f[last][x]); 
        last = x;
    }
    return 0;
} 
View Code

 

posted @ 2017-09-19 08:13  19992147  阅读(139)  评论(0编辑  收藏  举报