洛谷P3044 Relocation S

题目描述

Farmer John is moving! He is trying to find the best place to build a new farm so as to minimize the amount of travel he needs to do each day.

The region to which FJ plans to move has N towns (1 <= N <= 10,000). There are M bi-directional roads (1 <= M <= 50,000) connecting certain pairs of towns. All towns are reachable from each-other via some combination of roads. FJ needs your help selecting the best town as the home for his new farm.

There are markets in K of the towns (1 <= K <= 5) that FJ wants to visit every day. In particular, every day he plans to leave his new farm, visit the K towns with markets, and then return to his farm. FJ can visit the markets in any order he wishes. When selecting a town in which to build his new farm, FJ wants to choose only from the N-K towns that do not have markets, since housing prices are lower in those towns.

Please help FJ compute the minimum distance he will need to travel during his daily schedule, if he builds his farm in an optimal location and chooses his travel schedule to the markets as smartly as possible.

FJ决定搬家,重新建设农场,以便最小化他每天的行程。

FJ搬往的区域有N(1 <= N <= 10,000)个城镇,共有M (1 <= M <= 50,000)条双向道路连接某些城镇,所有城镇都能找到互通路线。

有K (1 <= K <= 5)个城镇建有市场,FJ每天离开新农场后,都要光顾这K个城镇,并返回农场。FJ希望建设农场的城镇不包含市场。

请帮助FJ选择最佳城镇建设农场,使得他每天的行程最小。

输入格式

* Line 1: Three space-separated integers, N, M, and K.

* Lines 2..1+K: Line i+1 contains an integer in the range 1...N identifying the town containing the ith market. Each market is in a different town.

* Lines 2+K..1+K+M: Each line contains 3 space-separated integers, i, j (1 <= i,j <= N), and L (1 <= L <= 1000), indicating the presence of a road of length L from town i to town j.

输出格式

* Line 1: The minimum distance FJ needs to travel during his daily routine, if he builds his farm in an optimal location.

输入输出样例

输入 #1复制

5 6 3 
1 
2 
3 
1 2 1 
1 5 2 
3 2 3 
3 4 5 
4 2 7 
4 5 10 

输出 #1复制

12 

说明/提示

There are 5 towns, with towns 1, 2, and 3 having markets. There are 6 roads.

FJ builds his farm in town 5. His daily schedule takes him through towns 5-1-2-3-2-1-5, for a total distance of 12.

上代码:

#include<iostream>
#include<cstdio>
#include<bits/stdc++.h>
using namespace std;
long long n,m,k,wz[6];
long long tot,head[10005],nx[100005],to[100005],w[100005];
long long dis[6][10005],vis[10005],f[2005][6];
void jia(long long aa,long long bb,long long cc)
{
	tot++;
	nx[tot]=head[aa];
	to[tot]=bb;
	w[tot]=cc;
	head[aa]=tot;
	return;
}
struct node
{
	long long id,val;
};
bool operator <(node aa,node bb)
{
	return aa.val>bb.val;
}
node bh(long long aa,long long bb)
{
	node tt;
	tt.id=aa;
	tt.val=bb;
	return tt;
}
void spfa(long long rt)//其实是dijkstra。。。
{
	priority_queue<node>q;
	q.push(bh(wz[rt],0));
	memset(vis,0,sizeof(vis));
	dis[rt][wz[rt]]=0;
	while(!q.empty())
	{
		node kk=q.top();
		q.pop();
		if(vis[kk.id]) continue;
		vis[kk.id]=1;
		for(long long i=head[kk.id];i;i=nx[i])
		{
			long long yy=to[i];
			if(dis[rt][yy]>dis[rt][kk.id]+w[i])
			{
				dis[rt][yy]=dis[rt][kk.id]+w[i];
				q.push(bh(yy,dis[rt][yy]));
			}
		}
	}
}
int main()
{
	memset(dis,0x3f3f3f3f,sizeof(dis));
	scanf("%lld%lld%lld",&n,&m,&k);
	for(long long i=1;i<=k;++i)
	{
		scanf("%lld",&wz[i]);
	}
	for(long long i=1;i<=m;++i)
	{
		long long x,y,z;
		scanf("%lld%lld%lld",&x,&y,&z);
		jia(x,y,z);
		jia(y,x,z);
	}
	for(long long i=1;i<=k;++i)
	{
		spfa(i);//预处理k个城镇到各点的距离
	}
	long long ans=0x3f3f3f3f;
	for(long long i=1;i<=n;++i)//枚举选的农场
	{
		long long flag=0;
		for(long long j=1;j<=k;++j) if(i==wz[j]) {flag=1;break;}
		if(flag) continue;//城镇不能选,不是吗?
		memset(f,0x3f3f3f,sizeof(f));
		for(long long j=1;j<=k;++j)
		{
			f[1<<(j-1)][j]=dis[j][i];//见上初始时
		}
		for(long long j=1;j<(1<<k);++j)
		{
			for(long long pp=1;pp<=k;++pp)//枚举当前所在的城镇
			if(j&(1<<(pp-1)))
			{
				for(long long qq=1;qq<=k;++qq)//枚举之前所在的城镇
				if(pp!=qq&&(j&(1<<(qq-1))))
				{
					f[j][pp]=min(f[j][pp],f[j^(1<<(pp-1))][qq]+dis[qq][wz[pp]]);//转移
				}
			}
		}
		for(long long j=1;j<=k;++j)//枚举最后所在的城镇
		{
			ans=min(ans,f[(1<<k)-1][j]+dis[j][i]);//取最小值
		}
	}
	printf("%lld",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值