感觉有点像网络流,但不会搞
看到数据范围又不由得往状压dp方面想
我们可以发现,一个图是优美的,则它的形状一定是一条从1~n的链,其中链上的每个点挂着一个子图
考虑dp[Mask][i]表示当前已经将Mask中的节点加入地图,主链的末端点是i的最大边权
考虑向后转移,有两种情况:
1. 向主链的后面添加一个节点,我们可以枚举Mask之外的每个点u,看i,u之间是否有边
即
dp[Mask|u][u]=min(dp[Mask|u][u],dp[Mask][i]+len(i,u))
d
p
[
M
a
s
k
|
u
]
[
u
]
=
m
i
n
(
d
p
[
M
a
s
k
|
u
]
[
u
]
,
d
p
[
M
a
s
k
]
[
i
]
+
l
e
n
(
i
,
u
)
)
2. 在u的下面挂一个子图,我们可以枚举Mask之外的子集
即
dp[Mask|sub][i]=min(dp[Mask|sub][i],dp[Mask][i]+sum[sub|i])
d
p
[
M
a
s
k
|
s
u
b
]
[
i
]
=
m
i
n
(
d
p
[
M
a
s
k
|
s
u
b
]
[
i
]
,
d
p
[
M
a
s
k
]
[
i
]
+
s
u
m
[
s
u
b
|
i
]
)
其中sum[S]表示连接点集S中的点的边的权值和,这个是可以
O(2n∗m)
O
(
2
n
∗
m
)
预处理的
所以我们的总复杂度为
O(2n∗m+2n∗n+3n)
O
(
2
n
∗
m
+
2
n
∗
n
+
3
n
)
用spfa序转移足以通过此题
#include <bits/stdc++.h>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pLL pair<LL,LL>
#define pii pair<double,double>
#define pb push_back
#define mp make_pair
#define pf push_front
#define LOWBIT(x) x & (-x)
using namespace std;
const int INF=2e9;
const LL LINF=2e16;
const int magic=348;
const double eps=1e-5;
const int MOD=998244353;
const double pi=acos(-1);
inline int getint()
{
bool f;char ch;int res;
while (!isdigit(ch=getchar()) && ch!='-') {}
if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
while (isdigit(ch=getchar())) res=res*10+ch-'0';
return f?res:-res;
}
vector<Pair> v[48];int ga[48][48];
queue<int> q;bool inq[200048][28];
int dp[200048][28],sum[200048];
int n,m;
inline void init_sum()
{
int Mask,i,j;
for (Mask=0;Mask<=(1<<n)-1;Mask++)
{
for (i=1;i<=n;i++)
if (Mask&(1<<(i-1)))
for (j=0;j<int(v[i].size());j++)
if (Mask&(1<<(v[i][j].x-1))) sum[Mask]+=v[i][j].y;
sum[Mask]>>=1;
}
}
int main ()
{
int i,x,y,c,Mask,rem,sub,cur,tocur,toMask;
n=getint();m=getint();memset(ga,0,sizeof(ga));
for (i=1;i<=m;i++)
{
x=getint();y=getint();c=getint();
v[x].pb(mp(y,c));v[y].pb(mp(x,c));
ga[x][y]=ga[y][x]=c;
}
init_sum();
memset(dp,0,sizeof(dp));memset(inq,false,sizeof(inq));
q.push(1);q.push(1);inq[1][1]=true;
while (!q.empty())
{
Mask=q.front();q.pop();cur=q.front();q.pop();
inq[Mask][cur]=false;
for (i=1;i<=n;i++)
if (!(Mask&(1<<(i-1))) && ga[cur][i])
{
tocur=i;toMask=(Mask|(1<<(i-1)));
if (dp[toMask][tocur]<dp[Mask][cur]+ga[cur][tocur])
{
dp[toMask][tocur]=dp[Mask][cur]+ga[cur][tocur];
if (!inq[toMask][tocur]) inq[toMask][tocur]=true,q.push(toMask),q.push(tocur);
}
}
rem=(1<<n)-1-Mask;
for (sub=rem;sub;sub=rem&(sub-1))
{
tocur=cur;toMask=(Mask|sub);
if (dp[toMask][tocur]<dp[Mask][cur]+sum[sub|(1<<(cur-1))])
{
dp[toMask][tocur]=dp[Mask][cur]+sum[sub|(1<<(cur-1))];
if (!inq[toMask][tocur]) inq[toMask][tocur]=true,q.push(toMask),q.push(tocur);
}
}
}
printf("%d\n",dp[(1<<n)-1][n]);
return 0;
}