全排列枚举单源最短路问题 ---另解状压dp

 

 AcWing 1135. 新年好 - AcWing

我们需要求 遍历图中的 起点 a b c d e 这6个点 的最短路径之和  我们发现每两个点之间可以看作单源最短路问题 那么思路是枚举遍历的顺序 每个顺序做5次最短路  这样的时间为 5!*mlogn  显然不是一个非常乐观的时间。

我们采取的方案是先跑最短路 用二维数组存储不同起点的最短路     然后再全排列枚举                  达到   空间换时间  的效果。

#include<bits/stdc++.h>
using namespace std;
const int N=200010;
typedef pair<int,int>PII;
int n,m;
int d[10];
int h[N],e[N],ne[N],w[N],idx;
int dist[10][N];
bool st[N];
int path[10];//记录顺序
int ans=0x3f3f3f3f;
void add(int a,int b,int c)
{
    e[idx]=b;ne[idx]=h[a];w[idx]=c;h[a]=idx++;
}

void dijkstra(int start)
{  
    memset(st,0,sizeof st);
    priority_queue<PII,vector<PII>,greater<PII>>heap;
    heap.push({0,d[start]});
    dist[start][d[start]]=0;
    while(!heap.empty())
    {
        auto t=heap.top();
        heap.pop();
        int dis=t.first,ver=t.second;
        if(st[ver])continue;
        st[ver]=true;
        for(int i=h[ver];i!=-1;i=ne[i])
        {
            int z=e[i];
            if(dist[start][z]>dist[start][ver]+w[i])
           { dist[start][z]=dist[start][ver]+w[i];
             heap.push({dist[start][z],z});
           }
        }
    }
}

bool stu[10];

void dfs(int u)
{
    if(u==6)
    {  int res=0;
      res=dist[6][d[path[1]]];
      for(int i=1;i<5;i++)
      {  
          res+=dist[path[i]][d[path[i+1]]];
      }
      ans=min(res,ans);
    }

    for(int i=1;i<=5;i++)
    {
        if(!stu[i])
        {
           path[u]=i;
           stu[i]=true;
           dfs(u+1);
           stu[i]=false;
        }
    }
}


int main()
{
    cin>>n>>m;
    for(int i=1;i<=5;i++)
    {
        cin>>d[i];
    }
    memset(h,-1,sizeof h);
    memset(dist,0x3f,sizeof dist);
   for(int i=0;i<m;i++)
   {
       int a,b,c;
       cin>>a>>b>>c;
       add(a,b,c);
       add(b,a,c);
   }
     d[6]=1;
     dijkstra(6);
    for(int i=1;i<=5;i++)
   {
       dijkstra(i);//以d[i]为起点
   }
     dfs(1);
   cout<<ans<<endl;
}

作者:逢时
链接:https://www.acwing.com/activity/content/code/content/6784034/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

给出状压dp的代码  :  

#include <bits/stdc++.h>
using namespace std;
#define db  double
#define ll  long long
#define Pir pair<int, int>
#define fi  first
#define se  second
#define pb  push_back
#define m_p make_pair
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
/*==========ACMer===========*/
const int N = 5e4 + 10, M = 2e5 + 10, num = 6;
int n, m;
struct Edge
{
    int v, w, ne;
} e[M];
int h[N], tot;
int d[10][10];
vector<int> vc;
int f[num][1 << num];
int vis[N], dis[N];

void add(int u, int v, int w)
{
    e[++ tot] = { v, w, h[u] }; h[u] = tot;
}

void dijkstra(int s)
{
    memset(vis, 0, sizeof vis);
    memset(dis, inf, sizeof dis);
    dis[s] = 0;
    priority_queue<Pir, vector<Pir>, greater<Pir>> q;
    q.push({ 0, s });
    while (q.size())
    {
        int u = q.top().se; q.pop();
        if (vis[u]) continue;
        vis[u] = 1;

        for (int i = h[u]; i; i = e[i].ne) {
            int v = e[i].v, w = e[i].w;
            if (dis[v] > dis[u] + w)
            {
                dis[v] = dis[u] + w;
                q.push({ dis[v], v });
            }
        }
    }
}



int main()
{
    scanf("%d %d", &n, &m);
    for (int i = 0; i < 5; i ++) {
        int x; scanf("%d", &x);
        vc.pb(x);
    }
    vc.pb(1);

    int u, v, w;
    for (int i = 0; i < m; i ++) {
        scanf("%d %d %d", &u, &v, &w);
        add(u, v, w);
        add(v, u, w);
    }

    for (int i = 0; i < vc.size(); i ++) {
        dijkstra(vc[i]);
        for (int j = 0; j < vc.size(); j ++) {
            d[i][j] = d[j][i] = dis[vc[j]];
        }
    }

    int cnt = 5;
    int S = (1 << cnt) - 1;
    memset(f, inf, sizeof f);
    for (int i = 0; i < cnt; i ++) {
        f[i][1 << i] = d[vc.size() - 1][i];
    }

    for (int s = 1; s <= S; s ++) {
        for (int i = 0; i < cnt; i ++) {
            if ((s >> i & 1) == 0)
            {
                for (int j = 0; j < cnt; j ++) {
                    if (s >> j & 1)
                    {
                        f[i][s | 1 << i] = min(f[i][s | 1 << i], f[j][s] + d[j][i]);
                    }
                }
            }
        }
    }

    int ans = inf;
    for (int i = 0; i < cnt; i ++) {
        ans = min(ans, f[i][S]);
    }
    printf("%d\n", ans);


    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逢时976

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值