题目链接:https://www.luogu.com.cn/problem/P1772
这道题有几种解法…
看到
m
<
=
20
m<=20
m<=20,想到状压
d
p
dp
dp
设
d
p
[
i
]
[
s
]
dp[i][s]
dp[i][s]表示前
i
i
i天中,第
i
i
i天状态为
s
s
s的最小花费
f
[
s
]
f[s]
f[s]为每天的转移状态
先要记忆化
d
f
s
dfs
dfs处理出
f
f
f数组
d
p
[
i
]
[
s
]
=
m
i
n
(
d
p
[
i
−
1
]
[
s
]
+
f
[
s
]
,
m
i
n
(
d
p
[
i
−
1
]
)
+
f
[
s
]
+
k
)
dp[i][s]=min(dp[i-1][s]+f[s],min(dp[i-1])+f[s]+k)
dp[i][s]=min(dp[i−1][s]+f[s],min(dp[i−1])+f[s]+k)
其中
m
i
n
(
d
p
[
i
−
1
]
)
min(dp[i-1])
min(dp[i−1])表示最小的前
i
−
1
i-1
i−1天 的最小花费可能
d
p
dp
dp数组在空间上可以滚动降维
至于时间上的优化,第
1
1
1个点和第
n
n
n个点都必须在状态中,可以这样优化单次转移状态数
时间复杂度
O
(
n
∗
2
m
−
2
)
O(n*2^{m-2})
O(n∗2m−2)
(不开
l
o
n
g
l
o
n
g
long\ long
long long见祖宗)
C o d e Code Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXS=1<<20,MAXM=20,MAXN=100;
const int inf=1<<30;
int dp[MAXS+10],f[MAXS+10],g[MAXM+10][MAXM+10],m;
bool vis[MAXN+10][MAXM+10];
inline int read();
void dfs(int,int,int);
signed main(){
//freopen ("std.in","r",stdin);
//freopen ("std.out","w",stdout);
int n,k,e,s;
int mn=0;
n=read(),m=read(),k=read(),e=read();
for (register int i=1;i<=e;++i){
int x=read(),y=read(),z=read();
if (!g[x][y]) g[x][y]=g[y][x]=z;
else g[x][y]=g[y][x]=min(g[x][y],z);
}
int d=read();
for (register int i=1;i<=d;++i){
int p=read(),a=read(),b=read();
for (register int j=a;j<=b;++j) vis[j][p]=1;
}
for (register int i=2;i< (1<<m) ;++i) f[i]=inf;
dfs(1,1,0); s=1<<m-2;
for (register int i=1;i<=n;++i){
int x=0,z=inf;
for (register int j=1;j<=m;++j)
if (vis[i][j]) x |= 1<<j-1;
for (register int j=0;j<s;++j){
int y= (j<<1) | (1 | (1<<m-1)); //第1个点和第n个点必然在状态中
if (x&y){
dp[y]=inf;
continue;
}
dp[y]=min(dp[y]+f[y], f[y]+mn+k);
z=min(z,dp[y]);
}
mn=z;
}
printf("%lld\n",mn);
return 0;
}
inline int read(){
int x=0;
char c=getchar();
while (!isdigit(c))c=getchar();
while (isdigit(c))x=(x<<1)+(x<<3)+(c&15),c=getchar();
return x;
}
void dfs(int x,int s,int sum){
if (f[s] <= sum && s!=1) return;
f[s]=sum;
if (x==m) return;
for (register int i=1;i<=m;++i){
if (g[x][i] && ((1<<i-1)&s)==0)
dfs(i,s|(1<<i-1),sum+g[x][i]);
}
}