【最短路】【DP】出行 trip

出行

trip.pas/c/cpp

1s/64MB

 

【题目描述】

某人打算外出旅游,他从起点城市1出发,计划到达城市n。城市之间被一些航线连通, 航线可以从任意方向飞行。由于是航空公司会员,他获得一次半价(半价以后价格只保留整数部分)机票的折扣券,使用的时机可以任意安排。

【输入】

输入第一行包含两个数n, m,表示城市数量和航线数量。

接下来的m行每行有3个数ai, bi, wi,分别表示第i条航线连接的第一个城市和第二个城市,以及航线的费用。

【输出】

输出一个整数,表示路途中花费的最小值。

【输出样例】

3 3

1 2 3

2 3 4

3 1 8

 

【输出样例】

4

 

【样例解释】

直接从 1号城市飞到3号城市并出示折扣券是最优方案

 

【数据规模】

对于30%的数据,n<=100,m<=100

对于50%的数据,n<=1000,m<=1500

对于所有数据,2<=n<=10000,1<=m<=100000, 1<=ai, bi<=n, wi<=10000,1<=n<=m。

保证存在一条路径可以从城市1到城市n的飞行方案






完成情况(cena测评)




本题实质上就是一个最短路,不过多了一个所谓的的优惠券

考试的时候写堆优的时候手残了一点!


一个简单的方法,我们可以再最短路的基础上加一维

用 d i st [ i ] [ 0 ] 表示走到 i 这个点还没用优惠券,用 d i s t [ i ] [ 1 ] 表示走到 i 这个店用了优惠券

那么我们就可以得到转移方程

f [ i ] [ 0 ] = m i n ( f [ i ] [ 0 ] , f [ j ] [ 0 ] + m a p [ i ] [ j ] )

f [ i ] [ 1 ] = m i n ( f [ i ] [ 1 ] , f [ j ] [ 0 ] + m a p [ i ] [ j ] / 2 )

f [ i ] [ 1 ] = m i n ( f [ i ] [ 1 ] , f [ j ] [ 1 ] + m a p [ i ] [ j ] )

这样就只需要在dijkstra里面套一个DP即可

不过考虑到数据范围是10000,所以写了一个堆优dijkstra


C++ AC Code


/*http://blog.csdn.net/jiangzh7
By Jiangzh*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<utility>
using namespace std;
const int N=10000+10;
const int V=100000+10;
const int inf=0x3f3f3f3f;

int n,m;
struct link{int y,z;link *next;}*head[N];
int dist[N][2];
bool h[N];
typedef pair<int,int> pii;
priority_queue<pii,vector<pii>,greater<pii> > Q;

void inlink(int x,int y,int z)
{
	link *node=new link;
	node->y=y;node->z=z;
	node->next=head[x];
	head[x]=node;
}

void read()
{
	freopen("trip.in","r",stdin);
	freopen("trip.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		inlink(x,y,z);inlink(y,x,z);
	}
}

void work()
{
	memset(dist,0x3f,sizeof(dist));
	dist[1][0]=dist[1][1]=0;
	Q.push(make_pair(0,1));
	while(!Q.empty())
	{
		pii u=Q.top();Q.pop();
		int k=u.second;
		if(h[k]) continue;
		h[k]=true;
		for(link *node=head[k];node;node=node->next)
		if(!h[node->y])
		{
			dist[node->y][0]=min(dist[node->y][0],dist[k][0]+node->z);
			dist[node->y][1]=min(dist[node->y][1],dist[k][1]+node->z);
			dist[node->y][1]=min(dist[node->y][1],dist[k][0]+node->z/2);
			Q.push(make_pair(min(dist[node->y][0],dist[node->y][1]),node->y));
		}
	}
	printf("%d\n",dist[n][1]);
}

int main()
{
	read();
	work();
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值