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(\(2^n*n^2\))
// 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;
}
标签:哈密顿,int,状压,long,Limit,https,dp,define
From: https://www.cnblogs.com/mathiter/p/18104044