[计蒜客20191103D] 坐车

n 个学生将要坐车去餐厅,每辆车最多可以坐 5 个人并且出于对环境的考虑他们不会使用多余的车.车的速度为每秒 1 个单位。现在 ii 号同学需要去 \(i\) 号点停 5 分钟(此时整车都在 i 号点等待),他们现在希望最小化花费时间最长的车花费的时间. 0 号点为起点,\(n+1\) 号点为餐厅

输入格式
第一行两个整数分别表示 \(n,m\)

接下来 m 行每行三个整数分别是 u,v,w,表示这条路连接 u,v 长度为 w

输出格式
输出花费时间最长的车花费时间最小为多少

数据范围
对于 30% 的数据,$ 1 \leq n \leq 5$

对于 50% 的数据, \(1 \leq n \leq 10\)

对于 100% 的数据,$ 1 \leq n \leq 15,1 \leq m \leq 1000,0 \leq u,v \leq n+1,1 \leq w \leq 10^7$
7

输出时每行末尾的多余空格,不影响答案正确性

样例输入

7 15
0 1 100
8 1 100
0 2 100
8 2 100
0 3 100
8 3 100
0 3 50
3 4 50
3 5 40
1 5 50
5 6 20
1 6 20
3 6 10
6 7 10
7 8 10

样例输出复制

280

首先可以用Floyd算出任意两点之间的距离。
然后可以暴力枚举怎么分组,每一组暴力看按什么顺序会最优。但是这样会超时。
所以我们在枚举出来每一组后记下来这一种分配全排列的最优值。也就是说,如果有一次分出来(1,2,3,4,5)一组,那么就计算完后记录答案,下一次把(1,2,3,4,5)分到一组时,就可以直接回答。这样就可以过了。

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int u,v,w,n,m;
int dp[25][25],t[25],st[5][10],jyh[25][25][25][25][25];
long long ans=1LL*1e18,cnt,ret;
long long check(int x,int g[25])
{
	if(jyh[g[1]][g[2]][g[3]][g[4]][g[5]])
		return jyh[g[1]][g[2]][g[3]][g[4]][g[5]];
	ret=1000000000,t;
	do
	{
		long long t=0;
		for(int i=2;i<=x;i++)
			t+=dp[g[i]][g[i-1]];
		t+=dp[0][g[1]]+dp[g[x]][n+1];
		ret=min(ret,t);
	}while(next_permutation(g+1,g+x+1));
	return jyh[g[1]][g[2]][g[3]][g[4]][g[5]]=ret+x*5;
}
void dfs(int x)
{
	if(x>n)
	{
		cnt=0;
		for(int i=1;i<=m;i++)
			cnt=max(check(t[i],st[i]),cnt);			
		ans=min(ans,cnt);
	}
	for(int i=1;i<=m;i++)
	{
		if(t[i]<5)
		{
			st[i][++t[i]]=x;
			dfs(x+1);
			st[i][t[i]--]=0;
		}
	}
}
int main()
{
	memset(dp,0x3f,sizeof(dp));
	cin>>n>>m;
	while(m--)
	{
		cin>>u>>v>>w;
		dp[u][v]=dp[v][u]=min(dp[u][v],w);
	}
	for(int k=0;k<=n+1;k++)
		for(int i=0;i<=n+1;i++)
			for(int j=0;j<=n+1;j++)
				dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
	
	m=(n-1)/5+1;
	dfs(1);
	cout<<ans<<endl;
}
posted @ 2022-05-31 17:12  灰鲭鲨  阅读(96)  评论(2编辑  收藏  举报