首页 > 代码库 > [codevs2800]送外卖

[codevs2800]送外卖

[codevs2800]送外卖

试题描述

有一个送外卖的,他手上有n份订单,他要把n份东西,分别送达n个不同的客户的手上。n个不同的客户分别在1~n个编号的城市中。送外卖的从0号城市出发,然后n个城市都要走一次(一个城市可以走多次),最后还要回到0点(他的单位),请问最短时间是多少。现在已知任意两个城市的直接通路的时间。

输入

第一行一个正整数n (1<=n<=15)

接下来是一个(n+1)*(n+1)的矩阵,矩阵中的数均为不超过10000的正整数。矩阵的i行j列表示第i-1号城市和j-1号城市之间直接通路的时间。当然城市a到城市b的直接通路时间和城市b到城市a的直接通路时间不一定相同,也就是说道路都是单向的。

输出

一个正整数表示最少花费的时间

输入示例

3
0 1 10 10
1 0 1 2
10 1 0 10
10 2 10 0

输出示例

8

数据规模及约定

1<=n<=15

题解

floyd 预处理之后状压 dp。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;

int read() {
	int x = 0, f = 1; char c = getchar();
	while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); }
	while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); }
	return x * f;
}

#define maxn 20
#define maxs 65536
#define oo 2147483647

int n, A[maxn][maxn], f[maxs][maxn];

void up(int& a, int b) {
	a = min(a, b);
	return ;
}

int main() {
	scanf("%d", &n);
	for(int i = 0; i <= n; i++)
		for(int j = 0; j <= n; j++) scanf("%d", &A[i][j]);
	
	for(int k = 0; k <= n; k++)
		for(int i = 0; i <= n; i++)
			for(int j = 0; j <= n; j++) up(A[i][j], A[i][k] + A[k][j]);
	int all = (1 << n + 1) - 1;
	for(int S = 0; S <= all; S++)
		for(int u = 0; u <= n; u++) f[S][u] = oo;
	f[1][0] = 0;
	for(int S = 1; S <= all; S++)
		for(int u = 0; u <= n; u++) if(f[S][u] < oo)
			for(int v = 0; v <= n; v++) up(f[S|(1<<v)][v], f[S][u] + A[u][v]);
	
	printf("%d\n", f[all][0]);
	
	return 0;
}

sb codevs 最后一组数据只给了 n*n 的矩阵,而不是 (n+1)*(n+1) 的矩阵,只能用 scanf 过。。。

[codevs2800]送外卖