专栏文章

二维/分层图模版题解(例题:传送门)

题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqef666
此快照首次捕获于
2025/12/04 03:27
3 个月前
此快照最后确认于
2025/12/04 03:27
3 个月前
查看原文
DescriptionDescription FJFJ 每天都要从家里去牧场,再从牧场回家……
FJFJ从家到牧场的地区可以看作一个NN个点和MM条双向边的图,家在1号点,牧场在NN号点。
现在FJ掌握了现代科技,他现在要将一些道路的两端修建双向传送的传送门,这样可以把通过的时间变为00
现在FJ最多可以建KK个传送门,FJ想知道他从家到牧场最少需要多少时间?
InputFormatInput Format 第一行,三个数NNMMKK
接下来M 行,每行三个数,表示一条边的两端和长度
OutputFormatOutput Format 一个数,表示最少要用多长时间 Sample 样例输入 4 4 1 1 2 10 2 4 10 1 3 1 3 4 100 样例输出 1

分层图定义: 分层图--------可以理解为有多个平行的图 第i层表示用了i张免费卷后到达每个点的最短路 显然,可以在同层跑最短路,而低层可以到高层 这就满足了在不同层间无后效性的拓展 于是我们可以设状态 其实简洁来说,以这道题为例就是相较单纯的距离dis多了一个目前使用多少传送门的状态 在题中可以用t表示,将原先dijk算法中的flag[]和dis[],更改为二维的形式,如:dis[点的坐标][使用传送门的数量] ,flag同理。 接下来是对dijk算法中的更改,首先对优先队列的定义需要三个变量:点的坐标,距离,使用传送门的数量用距离存小根堆。 剩下需要分两个判断 是否使用传送门 dis[y][t]>dis[x][t]+e[i].w不使用 dis[y][t+1]>dis[x][t]使用 之后依次循环直到空。

代码如下
using namespace std;
#define maxx 11454810
#define N 10011
int dis[N][30]={0},head[100000];
int flag[N][30];
int n,m,k,f,cnt=0,p;

int tim[100000]={0};
int ans[100000]={0};
int w[100000]={0};
int ei;
struct edge{
	int to,w,next=0;
}e[100000];

struct df{
	int x,t,dis;
};
bool operator<(const df & a,const df & b)
{
	if(a.dis==b.dis)
	{
		return a.t>b.t;
	}
	else
	{
		return a.dis>b.dis;
	}
}
priority_queue<df>q;

void Shion()
{
	for(int i=0;i<=N-1;i++)
	{
		for(int j=0;j<=25;j++)
		{
			dis[i][j]=0x7fffffff;
		}
	}
	dis[1][0]=0;
	q.push(df{1,0,0});
	flag[1][0]=1;
	while(!q.empty())
	{
		df tmp=q.top();
		int x=tmp.x,t=tmp.t;
		q.pop();
		flag[x][t]=1;  //?
		
		for(int i=head[x];i;i=e[i].next)
		{
			int y=e[i].to;
			if(!flag[y][t]&&dis[y][t]>dis[x][t]+e[i].w) //不使用
			{
				dis[y][t]=dis[x][t]+e[i].w;
				if(!flag[y][t])
				{
					q.push(df{y,t,dis[y][t]});  
				}
			}
			if(t<k)
  				if(!flag[y][t+1]&&dis[y][t+1]>dis[x][t])//使用
				{
					dis[y][t+1]=dis[x][t];
					if(!flag[y][t+1])
					{
						q.push(df{y,t+1,dis[y][t+1]});
					}
				}
		}
	}
}
void add(int u,int v,int w) //起点u, 终点v, 权值w
{	
	cnt++;
	e[cnt].next=head[u];
	e[cnt].to=v;
	e[cnt].w=w;
	head[u]=cnt;
}
signed main()
{	
	cin>>n>>m>>k;
	for(int i=1;i<=m;i++)
	{
		int a,b,c;
		cin>>a>>b>>c;
		add(a,b,c);
		add(b,a,c);
	}
	Shion();
	int minn=0x7fffffff;
	for(int i=0;i<=k;i++)
	{
		if(dis[n][i]<minn)
		{
			minn=dis[n][i];
		}
	}
	cout<<minn;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...