hdu6166-最短路&二进制枚举-Senior Pan

http://acm.hdu.edu.cn/showproblem.php?pid=6166
给定一个有向图,再给你一个集合。问这些集合中 两个点之间相互的最短路距离最小是多少。
思路:集合中每个数二进制都有一位不相同,
所以通过枚举二进制可以保证 包含了所有 两两枚举的情况。
然后dij的思路 就是通过 贪心+集合+有限的松弛操作 来搞事情的。
所以也可以计算集合之间的最短路,(学了一招qwq)
(关于为啥这样是最短的,我感觉在这里就像理解一个广搜一样。。)

#include <bits/stdc++.h>
using namespace std;
/*   dij在过程中,是通过贪心+松弛+集合 来判断的。

*/
typedef long long ll;
const int maxn=5e6+2000;
int m,n,k;
int a[maxn];
bool vis[maxn];
ll dis[maxn];
struct Edge{
      int to,next,cost;
}edge[maxn];
int len;
int head[maxn];
void add(int a,int b,int c){
    edge[len].to=b;
    edge[len].cost=c;
    edge[len].next=head[a];
    head[a]=len++;
}
struct Node{
     int to;
     ll cost;
      Node(){};
      Node(int _a,ll _b){to=_a,cost=_b;};
       friend bool operator < (Node a, Node b)
      {
       return a.cost>b.cost;    //x小的优先级高。
      }
};
priority_queue<Node>q;
ll  dij(){
      while(!q.empty()){
            Node u=q.top();
              q.pop();
            if(vis[u.to])
                return u.cost;
            for(int i=head[u.to];i!=-1;i=edge[i].next){
                 int to=edge[i].to;
                ll  cos=1ll*edge[i].cost;
                 if(cos+u.cost<dis[to]){
                     dis[to]=cos+u.cost;
                     q.push(Node(to,dis[to]));
                 }
            }
      }
}
void INIT(){
   for(int i=0;i<=m;i++)
    dis[i]=1e16;
   memset(vis,false,sizeof(vis));
   while(!q.empty())
     q.pop();
}
void init(){
      memset(head,-1,sizeof(head));
       len=0;
}
ll   solve(){
      ll ans=1e16;
      for(int i=0;i<20;i++){
          INIT();
          for(int j=0;j<k;j++){
              if((1<<i)&a[j]){
                dis[a[j]]=0;
                q.push(Node(a[j],0));
              }
              else
                vis[a[j]]=true;
          }
          INIT();
          for(int j=0;j<k;j++){
              if(!((1<<i)&a[j])){
                dis[a[j]]=0;
                q.push(Node(a[j],0));
              }
              else
                vis[a[j]]=true;
          }
          ans=min(ans,dij());
    }
   return ans;
}
int main(){
    //freopen("F:\\ttt\\100dddd6.txt","r",stdin);
    //freopen("F:\\ttt\\ou1.txt","w",stdout);
    int t,a1,b1,c1;
    scanf("%d",&t);
    for(int tt=1;tt<=t;tt++){
         init();
         scanf("%d%d",&m,&n);
          for(int i=0;i<n;i++){
              scanf("%d%d%d",&a1,&b1,&c1);
              add(a1,b1,c1);
          }
          scanf("%d",&k);
          for(int i=0;i<k;i++){
              scanf("%d",&a[i]);
          }
          printf("Case #%d: %lld\n",tt,solve());
    }
   return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值