bzoj3380: [Usaco2004 Open]Cave Cows 1 洞穴里的牛之一(spfa+状压DP)

数据最多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\n", ans);
44     return 0;
45 }

 

转载于:https://www.cnblogs.com/mzl120918/p/6063418.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值