数据最多14个有宝藏的地方,所以可以想到用状压dp
可以先预处理出每个i到j的路径中最小权值的最大值dis[i][j]
本来想用Floyd写,无奈太弱调不出来。。后来改用spfa
然后进行dp,这基本是货郎担问题(TSP),状压中挺常出现的问题
f[s][i]表示状态s下到第i个有宝藏的地方,是否能拿到所有s中的宝藏
当然最后还要考虑dis[id[i]][1]是否大于s状态下的宝藏数,取较小值就是答案了
跑了48ms,优化一下应该可以更快。。
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<queue> 5 #define INF 0x3f3f3f3f 6 using namespace std; 7 int n,m,K,id[20],dis[102][102],num,N,f[1<<14][15],ans,vis[102],mp[102][102]; 8 9 void get_dis(int num){ 10 queue<int> Q; memset(vis,0,sizeof(vis)); 11 Q.push(num); dis[num][num]=INF; vis[num]=1; 12 while (!Q.empty()){ 13 int now=Q.front(); Q.pop(); 14 for (int i=1; i<=n; i++){ 15 if (mp[now][i]!=0){ 16 dis[num][i]=max(dis[num][i],min(dis[num][now],mp[now][i])); 17 if (!vis[i]) Q.push(i),vis[i]=1; 18 } 19 } 20 } 21 } 22 23 int main(){ 24 scanf("%d%d%d", &n, &m, &K); 25 for (int i=1; i<=K; i++) scanf("%d", &id[i]); 26 memset(dis,0,sizeof(dis)); 27 for (int i=1,u,v,w; i<=m; i++) scanf("%d%d%d", &u, &v, &w),mp[v][u]=mp[u][v]=w; 28 for (int i=1; i<=n; i++) get_dis(i); 29 N=(1<<K); 30 for (int i=1; i<=K; i++) f[1<<(i-1)][i]=1; 31 for (int s=1; s<N; s++){ 32 num=0; 33 for (int i=1; i<=K; i++) if (s&(1<<(i-1))) num++; 34 for (int i=1; i<=K; i++) if (s&(1<<(i-1))){ 35 for (int j=1; j<=K; j++) if (!(s&(1<<(j-1)))) 36 if (num<=dis[id[i]][id[j]]) f[s^(1<<(j-1))][j]|=f[s][i]; 37 } 38 for (int i=1; i<=K; i++) if ((s&(1<<(i-1))) && f[s][i]){ 39 int t=min(num,dis[id[i]][1]); 40 ans=max(ans,t); 41 } 42 } 43 printf("%d ", ans); 44 return 0; 45 }