Negative Traveling Salesman
ABC 没题出了吗……全是大典
- 用邻接矩阵存下图
- 跑一遍 floyd 求出任意两点间的距离
- 同 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;
}