luogu P5340 [TJOI2019]大中鋒的遊樂場

背景:

昨晚志願簽名,然而鎮區的同學感受到了開車兩小時,簽名一分鐘。

題目傳送門:

https://www.luogu.org/problemnew/show/P5340

題意:

一個無向圖,每一條邊有一個長度,每一個點有一個值[1,1]∈[-1,1],現在你要找到一條最短路徑,使中間走過的點的權值和在任意時刻都[k,k]∈[-k,k]

思路:

好像是最短路。
然而條件不好保證。
k10k≤10,容易想到從這裏突破。
分層圖???
按照[k,k][-k,k]分層建圖,每兩層之間按照[1,0][-1,0]的需要連邊即可。
悄悄告訴你:從loj\text{loj}的數據來看,T=1T=1,多組數據是假的。

代碼:

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
queue<int> f;
	int n,m,k,st,ed,len;
	bool bz[500010];
	int last[500010],op[500010],dis[500010];
	struct node1{int x,y,z,next;} a[3000010];
	struct node2{int x,y,z;} b[200010];
int calc(int x,int y)
{
	return (x-1)*n+y;
}
void ins(int x,int y,int z)
{
	a[++len]=(node1){x,y,z,last[x]}; last[x]=len;
}
int spfa(int st,int ed)
{
	int ans=2147483647;
	memset(bz,false,sizeof(bz));
	bz[st]=true;
	memset(dis,63,sizeof(dis));
	dis[st]=0;
	while(!f.empty()) f.pop();
	f.push(st);
	while(!f.empty())
	{
		int x=f.front();
		f.pop();
		for(int i=last[x];i;i=a[i].next)
		{
			int y=a[i].y;
			if(dis[x]+a[i].z<dis[y])
			{
				dis[y]=dis[x]+a[i].z;
				if(!bz[y]) bz[y]=true,f.push(y);
			}
		}
		bz[x]=true;
	}
	for(int i=1;i<=2*k+1;i++)
		ans=min(ans,dis[calc(i,ed)]);
	return ans>=(int)(1e9)?-1:ans;
}

int main()
{
//	freopen("a.in","r",stdin);
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d %d %d",&n,&m,&k);
		for(int i=1;i<=n;i++)
			scanf("%d",&op[i]);
		for(int i=1;i<=m;i++)
			scanf("%d %d %d",&b[i].x,&b[i].y,&b[i].z);
		len=0;
		memset(last,0,sizeof(last));
		for(int i=1;i<=2*k+1-1;i++)
			for(int j=1;j<=m;j++)
			{
				if(op[b[j].x]==2) ins(calc(i,b[j].y),calc(i+1,b[j].x),b[j].z);
				if(op[b[j].y]==2) ins(calc(i,b[j].x),calc(i+1,b[j].y),b[j].z);
				
				if(op[b[j].x]==1) ins(calc(i+1,b[j].y),calc(i,b[j].x),b[j].z);
				if(op[b[j].y]==1) ins(calc(i+1,b[j].x),calc(i,b[j].y),b[j].z);
			}
		scanf("%d %d",&st,&ed);
		//printf("%d\n",op[st]==1?calc(k,st):calc(k+2,st));
		printf("%d\n",spfa(op[st]==1?calc(k,st):calc(k+2,st),ed));
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章