Live2D

最佳挑水 题解

最佳挑水

Description

小Y住在农村,离他的家不远有一口井,传说是小Y的祖先开掘的。虽然小Y的村子里通了自来水,但由于这口井的井水质量非常好,因此小Y家仍然喝这口井里的水。小Y非常喜欢这口井,所以他经常去挑水。
  小Y的家里有n(n是偶数)只桶,这些桶虽然大小相等,但是由于很多都有些破损,所以认为它们是不同的。小Y经常挑一根扁担(当然一定是带两只空桶)去井边挑水。小Y每次去井旁都会把桶中的水装到极限(假设水量无穷,且小Y都能够挑得动)。设小Y挑得是i,j两只桶,则挑水一趟需要走time[i,j]分钟。小Y想要在最少的时间内用自己的力量把家里所有的空桶装满。
  小Y觉得这是个难题,于是来找你帮忙编写一个程序来找出一种最佳挑水方案。

Input

输入文件中的的第一行为一个整数n(4<=n<=18)。
接下来的n行,每行有n个数,表示了time矩阵。其中:time矩阵中每一个数都是小于等于32768正整数,且time[i,i]是没有用的。
注意:time[i,j]=time[j,i]。

Output

输出文件中仅一行为一个数,即最佳挑水方案的最少时间。

Sample Input

4
0 100 5 100
100 0 100 11
5 100 0 100
100 11 100 0

Sample Output

16

题解

看到数据范围\(n≤18\)这么小,我们就可以愉快地考虑状压了
\(f[s]\)表示当前桶装满的状态为\(s\)所需要的最少时间(1表示装满,0表示没装),之后直接枚举两个点暴力转移DP就行了

CODE

#include<cstdio>
#include<string>
#include<cstring>
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define R register int
#define N 20
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int t[N][N],f[1<<N],n;
inline void read(int &x)
{
	x=0;int f=1;char ch=getchar();
	while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();x*=f;
}
int main()
{
	read(n);
	memset(f,inf,sizeof(f));
	for (R i=1;i<=n;++i)
		for (R j=1;j<=n;++j)
		{
			read(t[i][j]);if (i!=j) f[(1<<i-1)|(1<<j-1)]=t[i][j];
		}
	int tot=(1<<n)-1; 
	for (R s=1;s<=tot;++s)
	{
		int num=0;
		for (R i=1;i<=n;++i)
			if (s&(1<<i-1)) ++num;
		if (!(num&1))
			for (R i=1;i<=n;++i)
				for (R j=1;j<=n;++j)
					if (!(s&(1<<i-1)) && !(s&(1<<j-1))) f[(s|(1<<i-1))|(1<<j-1)]=min(f[(s|(1<<i-1))|(1<<j-1)],f[s]+t[i][j]);
	}
	printf("%d\n",f[tot]);
	return 0;
}
posted @ 2021-04-03 15:36  冷笑叹秋萧  阅读(143)  评论(0编辑  收藏  举报