2020牛客国庆集训派对day2

Description

(n le 10^4) 个点 (m le 10^4) 条边的无向图上,有 (k le 18) 个运输任务,每个任务从 (F_i)(D_i)。你只能同时处理一个任务。你可以从任何一点开始到任何一点结束。求运输所有任务的行走距离的最小值。

Solution

(f[i][S]) 表示最后一次运完第 (i) 个任务并停在 (D_i) 处,已经完成的运输任务的集合为 (S),此时的最小距离为多少。Dijkstra 或 SPFA 预处理后状压 DP 即可。

考场上这个题 WA 了无数发,最后发现数初始值设置小了——谨慎使用 memset 进行初始值设定……

#include <bits/stdc++.h>
using namespace std;

#define int long long 
const int N = 10005;
const int M = 25;
const int U = 600000;

#define reset(x) memset(x,0,sizeof x)
#define reset3f(x) memset(x,0x3f,sizeof x)

// 参数:点数n  源点v0
// 方法:make建边  reset_graph清图  solve计算
// 输出:d最短路数组
namespace sp {
vector<pair<int,int> > g[N];
int n,v0=1,d[N],v[N];
void make(int t1,int t2,int t3) {
    g[t1].push_back(make_pair(t2,t3));
    g[t2].push_back(make_pair(t1,t3));
}
void reset_graph() {
    for(int i=0;i<=n;i++) g[i].clear();
}
void solve(int _v0) {
    v0=_v0;
    queue <int> qu;
    for(int i=1;i<=n;i++) v[i]=0, d[i]=1e18;
    d[v0]=0; v[v0]=1; qu.push(v0);
    while(qu.size()) {
        int p=qu.front();
        qu.pop();
        v[p]=0;
        for(int i=0;i<g[p].size();i++) {
            int q=g[p][i].first,w=g[p][i].second;
            if(d[q]>d[p]+w) {
                d[q]=d[p]+w;
                if(!v[q]) qu.push(q), v[q]=1;
            }
        }
    }
}
}

int dist[M][M];

int n,m,k,t1,t2,t3,f[N],d[N],dp[M][U];

signed main()
{
    cin>>n>>m>>k;
    sp::n=n;
    for(int i=1;i<=m;i++)
    {
        cin>>t1>>t2>>t3;
        sp::make(t1,t2,t3);
    }
    for(int i=1;i<=k;i++)
    {
        cin>>f[i]>>d[i];
    }
    for(int i=1;i<=k;i++)
    {
        sp::solve(d[i]);
        for(int j=1;j<=k;j++)
        {
            dist[i][j]=sp::d[f[j]];
        }
    }
    for(int i=1;i<=k;i++)
    {
        for(int j=0;j<(1<<k);j++)
        {
            dp[i][j]=1e18;
        }
    }
    for(int i=1;i<=k;i++)
    {
        dp[i][1<<(i-1)]=dist[i][i];
    }

    for(int s=1;s<(1<<k);s++)
    {
        for(int i=1;i<=k;i++) if(s&(1<<(i-1)))
        {
            for(int j=1;j<=k;j++)
            {
                if(s&(1<<(j-1))) continue;
                dp[j][s|(1<<(j-1))]=min(dp[j][s|(1<<(j-1))],dp[i][s]+dist[i][j]+dist[j][j]);
            }
        }
    }

    int ans=1e18;
    for(int i=1;i<=k;i++)
    {
        ans=min(ans,dp[i][(1<<k)-1]);
    }
    if(ans>1e17)
    {
        cout<<-1<<endl;
    }
    else
    {
        cout<<ans<<endl;
    }
    
    return 0;
}

原文地址:https://www.cnblogs.com/mollnn/p/13797188.html