BZOJ1138: [POI2009]Baj 最短回文路

题目大意:给一个有向图,边权都是字母,给出D组询问,每组询问求从A到B的最短回文路长度


我们可以把一条回文路经(A,B)想象成从一个初始状态(在A,B在同一个点或者在同一条道路的两端)开始,然后B先随意走一步,接着A反着走一步边权和B走的那一步相同的边...以此类推

所以我们可以设一个状态F[i][j][k]表示当前A在i号点,B在j号点,上一步B走的是边权为k的边(如果上一步是A走的则k=0),这种状态下的最少边数

然后我们就可以转移了

若k=0,则让B随便走一步来扩展

若k=1,则让A反着走一步边权为k的边


时间复杂度的话,我个人感觉是O(NM*26)的,N=400,M=60000居然能过....

还要卡常数差评..不知道有没有什么更好的做法


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 410
#define M 60010
using namespace std;
int f[N][N][27];
struct ljb
{
	int to[M],nxt[M],pre[N],cnt,w[M];
	void ae(int ff,int tt,int ww)
	{
		cnt++;
		to[cnt]=tt;
		nxt[cnt]=pre[ff];
		pre[ff]=cnt;
		w[cnt]=ww;
	}
}Z,F;
struct ppp{int x,y,z;};
ppp q[N*N*27];
int h=1,t;
int a[N];
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	int i,j,k,x,y,z;
	char s[10];
	memset(f,0x3f,sizeof(f));
	for(i=1;i<=n;i++)
	{
		t++;q[t]=(ppp){i,i,0};
		f[i][i][0]=0;
	}
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%s",&x,&y,s);
		Z.ae(x,y,s[0]-96);
		F.ae(y,x,s[0]-96);
		if(f[x][y][0]==0x3f3f3f3f)
		{
			t++;q[t]=(ppp){x,y,0};
			f[x][y][0]=1;
		}
	}
	while(h<=t)
	{
		x=q[h].x;y=q[h].y;z=q[h].z;
		int step=f[x][y][z];
		h++;
		if(z==0)
		{
			for(i=Z.pre[y];i;i=Z.nxt[i])
			{
				j=Z.to[i];
				if(f[x][j][Z.w[i]]>step+1)
				{
					f[x][j][Z.w[i]]=step+1;
					t++;q[t]=(ppp){x,j,Z.w[i]};
				}
			}
		}
		else
		{
			for(i=F.pre[x];i;i=F.nxt[i])
			if(F.w[i]==z)
			{
				j=F.to[i];
				if(f[j][y][0]>step+1)
				{
					f[j][y][0]=step+1;
					t++;q[t]=(ppp){j,y,0};
				}
			}
		}
	}
	int D;
	scanf("%d",&D);
	for(i=1;i<=D;i++)
	scanf("%d",&a[i]);
	for(i=1;i<D;i++)
	{
		if(f[a[i]][a[i+1]][0]==0x3f3f3f3f) puts("-1");
		else printf("%d\n",f[a[i]][a[i+1]][0]);
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章