Negative Traveling Salesman

ABC 没题出了吗……全是大典

  1. 用邻接矩阵存下图
  2. 跑一遍 floyd 求出任意两点间的距离
  3. P1433 吃奶酪

吐槽结束,还是具体说说状压怎么做吧。 设计状态: 表示当前在 点,状态为 时代价的最小值。其中状态用二进制压位,第 个二进制位为 表示已经访问过 点,为 表示没有访问过。

假设当前想要求 。我们可以枚举 点,从该点走到这里。但是 有限制条件:

  • ,不能从当前点走到当前点;
  • 的第 个比特位为 ,必须之前走过第 个点才能从那走过来。

满足条件即可列出转移方程:

代码如下:

#include<bits/extc++.h>
using namespace std;
namespace pbds=__gnu_pbds;
using ui=unsigned int;
using uli=unsigned long long int;
using li=long long int;
int main(void){
    ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
    size_t n,m;
    cin>>n>>m;
    vector<vector<int>> dst(n,vector<int>(n,numeric_limits<int>::max()/2));
    while (m--){
        size_t u,v;int w;
        cin>>u>>v>>w;--u,--v;
        dst[u][v]=w;
    }
    for (size_t k=0;k<n;++k) for (size_t i=0;i<n;++i) for (size_t j=0;j<n;++j)
        dst[i][j]=min(dst[i][j],dst[i][k]+dst[k][j]);
    vector<vector<int>> dp(1<<n,vector<int>(n,numeric_limits<int>::max()/2));
    for (size_t i=0;i<n;++i) dp[1<<i][i]=0;
    for (size_t i=0;i<(1<<n);++i) if (__builtin_popcount(i)>1)
        for (size_t j=0;j<n;++j) if ((i|(1<<j))==i)
            for (size_t k=0;k<n;++k) if (k!=j&&(i&(1<<k)))
                dp[i][j]=min(dp[i][j],dp[i^(1<<j)][k]+dst[k][j]);
    int ans=numeric_limits<int>::max();
    for (size_t i=0;i<n;++i) ans=min(ans,dp[(1<<n)-1][i]);
    if (ans>=numeric_limits<int>::max()/8) cout<<"No"; else cout<<ans;
    return 0;
}
posted @ 2024-01-30 15:50  MrPython  阅读(9)  评论(0)    收藏  举报  来源