BZOJ 1138 POI2009 Baj 最短回文路 BFS

7 篇文章 0 订阅

+题目大意:给定一张有向图,每个点有一个字符,多次求两点的最短回文路

据说这道题第一次做的人都会T?
一开始的思路是这样的:令 fx,y 表示从点 x 走到点y的最短回文路径,转移 fx,y=min{fz,w+2|xc>z,wc>y}
然后广搜,果断T了= =

冗余的转移太多了……
正解是这样的:
gx,y,c 表示从点 x 走到点y,除了最后一条边之外是回文路径且最后一条边的字符为 c 的最短路
然后转移是这样的:
gx,y,c=min{fx,z+1|zc>y}
fx,y=min{gz,y,c+1|xc>z}
这样的复杂度是 O(nm+26n2) 的,就可以通过了

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 440
using namespace std;
struct abcd{
    int to,c,next;
}table[60600];
int head[M],tot;
int n,m;
int f[M][M],g[M][M][26];
pair<pair<int,int>,int> q[M*M*27];
int r,h;
vector<int> a[M][26];
void Add(int x,int y,int z)
{
    table[++tot].to=y;
    table[tot].c=z;
    table[tot].next=head[x];
    head[x]=tot;
}
void BFS()
{
    vector<int>::iterator it;
    int i;
    while(r!=h)
    {
        pair<pair<int,int>,int> temp=q[++h];
        int x=temp.first.first,y=temp.first.second;
        if(temp.second==-1)
        {
            for(i=head[y];i;i=table[i].next)
                if(g[x][table[i].to][table[i].c]==-1)
                    g[x][table[i].to][table[i].c]=f[x][y]+1,q[++r]=make_pair(make_pair(x,table[i].to),table[i].c);
        }
        else
        {
            for(it=a[x][temp.second].begin();it!=a[x][temp.second].end();it++)
                if(f[*it][y]==-1)
                    f[*it][y]=g[x][y][temp.second]+1,q[++r]=make_pair(make_pair(*it,y),-1);
        }
    }
}
int main()
{
    int i,x,y;
    char p[10];
    cin>>n>>m;
    memset(f,-1,sizeof f);
    memset(g,-1,sizeof g);
    for(i=1;i<=n;i++)
        f[i][i]=0,q[++r]=make_pair(make_pair(i,i),-1);
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%s",&x,&y,p+1);
        Add(x,y,p[1]-'a');
        a[y][p[1]-'a'].push_back(x);
        if(~f[x][y]) continue;
        f[x][y]=1,q[++r]=make_pair(make_pair(x,y),-1);
    }
    BFS();
    static int a[M],d;
    cin>>d;
    for(i=1;i<=d;i++)
        scanf("%d",&a[i]);
    for(i=2;i<=d;i++)
        printf("%d\n",f[a[i-1]][a[i]]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值