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]);
	}
}



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