[NOIP2017]宝藏

题目:洛谷P3959、UOJ#333、Vijos P2032。

题意:
给定一个有重边,边有权值的无向图。从某一个点出发,求到达所有的点需要的最少费用,
并且限制两点之间只有一条路径。
费用的计算公式为:所有边的费用之和。而边(x->y)的费用就为:y到初始点的距离 * 边权。
解题思路:
当时枚举边,拿了70分。
正解状压dp,状压方式貌似很多。
设\(f_i\)表示状态\(i\)下的最小费用,\(dis_{ij}\)表示状态\(i\)最小费用下点\(j\)到出发点的总点数,\(e_{ij}\)表示点\(i\)到\(j\)的最小边权。
则\(f_{i+2^j}=min(f_{i+2^j},f_i+dis_{ij}\times e_{jk})(j\in i, k\notin i)\)
边界\(f_{2^s}=0,dis_{2^s s}=1\)
当\(f_i\)更新时,\(dis_i\)需要整个更新。
然后对于每个起点,答案为\(f_{2^n-1}\),其最小值就是答案。
时间复杂度\(O(2^n n^4)\)。

C++ Code:

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
int n,m,e[13][13],ans=inf,f[1<<14|1],dis[1<<14|1][13];
inline int min(int a,int b){return a<b?a:b;}
inline int readint(){
	int c=getchar(),d=0;
	for(;!isdigit(c);c=getchar());
	for(;isdigit(c);c=getchar())
	d=(d<<3)+(d<<1)+(c^'0');
	return d;
}
int search(int s){
	memset(f,0x3f,sizeof f);
	f[1<<s]=0;
	memset(dis,0,sizeof dis);
	int N=1<<n;
	dis[1<<s][s]=1;
	for(int i=0;i<N;++i)
	for(int j=0;j<n;++j)
	if(i&(1<<j))
	for(int k=0,p;k<n;++k)
	if(!(i&(p=1<<k))&&(e[j][k]+1)){
		int nw=f[i]+dis[i][j]*e[j][k];
		if(nw<f[i|p]){
			f[i|p]=nw;
			memcpy(dis[i|p],dis[i],sizeof dis[i]);
			dis[i|p][k]=dis[i][j]+1;
		}
	}
	return f[N-1];
}
int main(){
	n=readint(),m=readint();
	memset(e,-1,sizeof e);
	for(int i=1;i<=m;++i){
		int u=readint()-1,v=readint()-1,t=readint();
		if(e[u][v]==-1||e[u][v]>t)e[u][v]=e[v][u]=t;
	}
	for(int i=0;i<n;++i)ans=min(ans,search(i));
	printf("%d\n",ans);
	return 0;
}

 

posted @ 2018-05-31 19:57  Mrsrz  阅读(414)  评论(0编辑  收藏  举报