一类哈密顿路径/回路为背景的状压dp

https://codeforces.com/contest/1950/problem/G

在非连通图上找到一条包含点最多的路径,dp数组维护可达性

// Problem: G. Shuffling Songs // Contest: Codeforces - Codeforces Round 937 (Div. 4) // URL: https://codeforces.com/contest/1950/problem/G // Memory Limit: 256 MB // Time Limit: 3000 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> using namespace std; #define ll long long //# define int long long #define ull unsigned long long #define pii pair<int,int> #define baoliu(x, y) cout << fixed << setprecision(y) << x #define endl "\n" #define debug1(x) cerr<<x<<" " #define debug2(x) cerr<<x<<endl const int N = 2e5 + 10; const int M = 1e6 + 10; const int inf = 0x3f3f3f3f; const int mod = 998244353; const double eps = 1e-8; int n, m; int a[N]; void solve(){ vector<string>v1; vector<string>v2; cin>>n; vector<vector<int>>w(n+1,vector<int>(n+1,0)); for(int i=0;i<n;i++){ string s1,s2;cin>>s1>>s2; v1.push_back(s1); v2.push_back(s2); } for(int i=0;i<n;i++){ for(int j=i;j<n;j++){ //if(j==i)continue; if(v1[i]==v1[j]||v2[i]==v2[j]){ w[i][j]=1;w[j][i]=1; } } } // for(int i=0;i<n;i++){ // for(int j=0;j<n;j++){ // cerr<<w[i][j]; // } // cerr<<endl; // } //寻找答案状态:枚举最终的状态和终点,从而计算答案 int ans=0; vector<vector<int>>dp((1<<n)+1,vector<int>(n+1,0)); //fill(dp[0].begin(),dp[0].end(),1); for(int i=0;i<n;i++)dp[1<<i][i]=1; for(int i=0;i<(1<<n);i++){ for(int j=0;j<n;j++){ int u=(i>>j)&1; if(u==0)continue; for(int k=0;k<n;k++){ //为什么不能判断终点j和k转移重复 //这会导致初始只有一个0基础态无法转移 int v=(i>>k)&1; if(v==0)continue; int last=i-(1<<j); dp[i][j]|=dp[last][k]&w[k][j]; // cerr<<i<<" "<<j<<endl; if(dp[i][j]){ ans=max(ans,__builtin_popcount(i)); } } } } cout<<n-ans<<endl; } int main() { cin.tie(0); ios::sync_with_stdio(false); int t; cin>>t; //t=1; while (t--) { solve(); } return 0; }

最短哈密顿路径

https://www.acwing.com/problem/content/93/

主要就是需要不重不漏的走一遍并且维护最短路,这无法在多项式时间内完成,在n不大的时候我们用二级制枚举所有状态,枚举终点作为状态,转移是通过枚举上一个点。

时间复杂度:O(2nn2)

// Problem: 最短Hamilton路径 // Contest: AcWing // URL: https://www.acwing.com/problem/content/93/ // Memory Limit: 256 MB // Time Limit: 5000 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> using namespace std; #define ll long long //# define int long long #define ull unsigned long long #define pii pair<int,int> #define baoliu(x, y) cout << fixed << setprecision(y) << x #define endl "\n" #define debug1(x) cerr<<x<<" " #define debug2(x) cerr<<x<<endl const int N = 21; const int M = 1e6 + 10; const int inf = 0x3f3f3f3f; const int mod = 998244353; const double eps = 1e-8; int n, m; int w[N][N]; //首先思考为什么这里最短路不能用普通的最短路 //首先它需要把所有点都遍历到,而普通最短路根本不在乎这个 int dp[1<<20][N]; void solve(){ cin>>n; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ cin>>w[i][j]; } } memset(dp,0x3f ,sizeof dp); dp[1][0]=0; for(int i=0;i<(1<<n);i++){ for(int j=0;j<n;j++){//枚举当前终点 if(((i>>j)&1)==0)continue; for(int k=0;k<n;k++){//枚举上一次转移点 if(((i>>k)&1)==0)continue; int pre=i-(1<<j); if(k==j)continue; dp[i][j]=min(dp[i][j],dp[pre][k]+w[k][j]); } } } int ed=(1<<n)-1; cout<<dp[ed][n-1]; } int main() { cin.tie(0); ios::sync_with_stdio(false); int t; //cin>>t; t=1; while (t--) { solve(); } return 0; }

最短哈密顿回路

https://www.luogu.com.cn/problem/P1171

// Problem: P1171 售货员的难题 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P1171 // Memory Limit: 125 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> using namespace std; #define ll long long //# define int long long #define ull unsigned long long #define pii pair<int,int> #define baoliu(x, y) cout << fixed << setprecision(y) << x #define endl "\n" #define debug1(x) cerr<<x<<" " #define debug2(x) cerr<<x<<endl const int N =21 ; const int M = 1e6 + 10; const int inf = 0x3f3f3f3f; const int mod = 998244353; const double eps = 1e-8; int n, m; int a[N]; int w[N][N]; //首先思考为什么这里最短路不能用普通的最短路 //首先它需要把所有点都遍历到,而普通最短路根本不在乎这个 int dp[1<<20][N]; void solve(){ cin>>n; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ cin>>w[i][j]; } } memset(dp,0x3f ,sizeof dp); dp[1][0]=0; for(int i=0;i<(1<<n);i++){ for(int j=0;j<n;j++){//枚举当前终点 if(((i>>j)&1)==0)continue; for(int k=0;k<n;k++){//枚举上一次转移点 if(((i>>k)&1)==0)continue; int pre=i-(1<<j); if(k==j)continue; dp[i][j]=min(dp[i][j],dp[pre][k]+w[k][j]); } } } int ed=(1<<n)-1; int ans=inf; for(int i=1;i<n;i++){ ans=min(ans,dp[ed][i]+w[i][0]); } cout<<ans<<endl; } int main() { cin.tie(0); ios::sync_with_stdio(false); int t; //cin>>t; t=1; while (t--) { solve(); } return 0; }

__EOF__

本文作者爱飞鱼
本文链接https://www.cnblogs.com/mathiter/p/18104044.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   potential-star  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示