hdu 4640(状压dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4640

思路:f[i][j]表示一个人状态i下走到j的最小花费,dp[i][j]表示i个人在状态j下的最下花费。首先我们可以一遍bfs求出f[i][j],然后通过f[i][j]得到dp[1][i],最后就是更新dp[i][j]了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7 #define inf 1<<30
 8 typedef pair<int,int>PP;
 9 
10 int map[20][20];
11 int f[1<<18][20];//派一个人去,在某状态下到达点v的最小花费
12 int dp[4][1<<18];//派i个人去,在某状态的最小花费
13 bool mark[1<<18][20];
14 int n,m,S,ans;
15 
16 void bfs()
17 {
18     queue<PP>que;
19     que.push(make_pair(0,0));
20     memset(mark,false,sizeof(mark));
21     for(int i=0;i<(1<<n);i++)
22         for(int j=0;j<n;j++)f[i][j]=inf;
23     f[0][0]=0;
24     while(!que.empty()){
25         PP p=que.front();
26         que.pop();
27         int s=p.first,u=p.second;
28         mark[s][u]=false;
29         for(int i=0;i<n;i++){
30             if(map[u][i]<inf&&f[s|(1<<i)][i]>f[s][u]+map[u][i]){
31                 f[s|(1<<i)][i]=f[s][u]+map[u][i];
32                 if(!mark[s|(1<<i)][i]){
33                     mark[s|(1<<i)][i]=true;
34                     que.push(make_pair(s|(1<<i),i));
35                 }
36             }
37         }
38     }
39 }
40 
41 void Solve()
42 {
43     for(int i=1;i<=3;i++)
44         for(int j=0;j<(1<<n);j++)dp[i][j]=inf;
45     for(int i=0;i<(1<<n);i++)
46         for(int j=0;j<n;j++)dp[1][i]=min(dp[1][i],f[i][j]);
47     for(int i=2;i<=3;i++){
48         for(int j=0;j<(1<<n);j++){
49             //枚举子集
50             for(int k=j;k;k=(k-1)&j){
51                 dp[i][j]=min(dp[i][j],max(dp[1][k|1],dp[i-1][(j^k)|1]));
52             }
53         }
54     }
55     ans=inf;
56     for(int i=1;i<=3;i++)
57         for(int j=0;j<(1<<n);j++)if((j&S)==S)ans=min(ans,dp[i][j]);
58     if(ans==inf)ans=-1;
59     printf("%d\n",ans);
60 }
61 
62 int main()
63 {
64     int _case,u,v,w,k,t=1;
65     scanf("%d",&_case);
66     while(_case--){
67         scanf("%d%d",&n,&m);
68         for(int i=0;i<=n;i++)
69             for(int j=0;j<=n;j++)map[i][j]=(i==j?0:inf);
70         while(m--){
71             scanf("%d%d%d",&u,&v,&w);
72             u--,v--;
73             map[u][v]=map[v][u]=min(map[u][v],w);
74         }
75         S=0;
76         scanf("%d",&k);
77         while(k--){
78             scanf("%d",&u);
79             u--;
80             S|=(1<<u);
81         }
82         bfs();
83         printf("Case %d: ",t++);
84         Solve();
85     }
86     return 0;
87 }
88 
89 
90 
91             
View Code

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值