ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SP1700题解

2022-08-07 10:01:56  阅读:114  来源: 互联网

标签:状态 cnt 题目 int 题解 状压 SP1700 车票


题目大意:

给你一些车票和一些城市,问你从 \(a\) 走到 \(b\) 怎么走才能使总花费时间最小,并且没有限制城市的先后顺序。

题目分析:

这里看到题目后,因为数据范围 \(1 \leqslant n \leqslant 8\) ,很容易就想到能用状压DP做,只不过这是在图上做DP。

但这里需要考虑一个很重要的问题,是对车票做状压还是对城市做状压?

我们这样想:

若是用城市来做状压,因为题目并没有规定先到哪一座,后到哪一座,所以城市是没有顺序的,也就是说你无法知道当前状态的上一个城市是哪一个,也就无法实现转移,所以我们这里只能对车票做状压。

然后三部曲:

1.设计状态:

这里我们设 \(dp_{i,j}\) 表示表示车票使用情况是二进制下的i时,当前走到了城市j。

2.状态转移:

很明显,当前状态肯定是由上一个城市的状态再加上在当前车票状态下,它们之间所耗时间,由于要求最小值,所以取 \(min\) 。

状态转移:

for(register int i=0;i<(1<<n);i++)//枚举车票情况 
{
	for(register int j=0;j<n;j++)//枚举到当前城市所用车票编号 
	{
		if(!(i&(1<<j)))//无效状态,舍去 
			continue;
		for(register int x=1;x<=m;x++)//枚举上一个到达的城市 
		{
			for(register int l=head[x];l;l=e[l].nxt)//遍历图 
			{
				int y=e[l].to;
				double z=e[l].len;
				dp[i][x]=min(dp[i][x],dp[i^(1<<j)][y]+z*1.0/t[j+1]);//状态转移 
			}
		}
	}
}

3.初始状态及输出:

题目给了我们起点 \(a\) ,所以初始状态就是将 \(dp_{0,a}\) 设为 \(0\) 。

输出是从所有的车票状态里找到到终点 \(b\) 所用的时间最小值,即:

for(register int i=0;i<(1<<n);i++)
	minn=min(minn,dp[i][b]);//在每种车票使用情况到终点所耗的时间中取最小值 

最后还要记得判断是否可以走到,详细见代码。

这里弱弱的问一句,为什么其他大佬都要用最短路,我没用好像也能过。

Code(带注释版)

#include<bits/stdc++.h>
using namespace std;
const int N=35;
const int MAXN=9; 
const int MAXM=1024;

struct Node
{
	int to,nxt;
	double len;
}e[MAXM];

int head[MAXM],cnt;

inline void add(int x,int y,int z)//链式前向星 
{
	e[++cnt].to=y;
	e[cnt].len=z;
	e[cnt].nxt=head[x];
	head[x]=cnt;
}

int n,m;
int p,a,b;
double t[MAXN+5];//马的数量 
double dp[1<<MAXN][N];//dp[i][j]表示车票使用情况是二进制下的i时,走到了城市j 

int main()
{
	while(scanf("%d%d%d%d%d",&n,&m,&p,&a,&b))
	{
		if(!n&&!m&&!p&&!a&&!b)//若均为0,则结束 
			return 0;
		cnt=0;
		memset(head,0,sizeof(head));//多组数据清空 
		for(register int i=0;i<(1<<n);i++)
		{
			for(register int j=1;j<=m;j++)
			{
				dp[i][j]=1e9;//将dp值设为极大值,后面好判断 
			}
		}
		for(register int i=1;i<=n;i++)
			scanf("%lf",&t[i]);//输入车票 
		for(register int i=1;i<=p;i++)
		{
			int x,y;
			double z;
			scanf("%d%d%lf",&x,&y,&z);
			add(x,y,z);
			add(y,x,z);//根据题目要求建双向边 
		}
		dp[0][a]=0;//到起点不需要车票,也不需要时间 
		for(register int i=0;i<(1<<n);i++)//枚举车票情况 
		{
			for(register int j=0;j<n;j++)//枚举到当前城市所用车票编号 
			{
				if(!(i&(1<<j)))//无效状态,舍去 
					continue;
				for(register int x=1;x<=m;x++)//枚举上一个到达的城市 
				{
					for(register int l=head[x];l;l=e[l].nxt)//遍历图 
					{
						int y=e[l].to;
						double z=e[l].len;
						dp[i][x]=min(dp[i][x],dp[i^(1<<j)][y]+z*1.0/t[j+1]);//状态转移 
					}
				}
			}
		}
		double minn=1e9;//设为极大值 
		for(register int i=0;i<(1<<n);i++)
		{
			minn=min(minn,dp[i][b]);//在每种车票使用情况到终点所耗的时间中取最小值 
		}
		if(minn!=1e9)//若有答案则输出 
		{
			printf("%.3lf\n",minn);
		}
		else
		{
			printf("Impossible\n");//否则输出Impossible
		}
	}
	return 0;
}

实测AC

标签:状态,cnt,题目,int,题解,状压,SP1700,车票
来源: https://www.cnblogs.com/yhx-error/p/16558500.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有