推歌:Masquerade
传送
其实没什么难度,只要读懂题了就可以秒了。
题意:
给定 \(n\) 个点 \(m\) 条边的无向图 \(G\),每条边有一个权值 \(w\) 和点集 \(S\)。
现在有一个点集 \(T\),初始只含有一个点。每次可以选择一条边 \((u,v,S,w)\),满足 \(u\in T\) 或 \(v\in T\),且 \(S\subseteq T\)。可以花费 \(w\) 的代价令 \(T\to T\cup \{u,v\}\)。
求令 \(T=\{1,2,\cdots,n\}\) 的最小花费。
看到 \(n\le 15\) 很容易想到状压,设 \(dp[T]\) 为当前点集为 \(T\) 的最小花费,每次转移暴力枚举边进行转移即可,实现是朴素的。
Code
#include <bits/stdc++.h>
using namespace std;
int n,m,dp[1<<15];
int u[380],v[380],T[380],w[380];
int main(){cin>>n>>m;for(int i=1;i<=m;i++){cin>>u[i]>>v[i]>>T[i]>>w[i];u[i]--,v[i]--;}memset(dp,0x3f,sizeof(dp));dp[0]=0;for(int i=0;i<n;i++)dp[1<<i]=0;for(int S=0;S<(1<<n);S++)for(int i=1;i<=m;i++){if((S&T[i])!=T[i])continue;int x=1<<u[i],y=1<<v[i];if(S&(x|y))dp[S|x|y]=min(dp[S|x|y],dp[S]+w[i]);}if(dp[(1<<n)-1]==0x3f3f3f3f)cout<<"-1"<<endl;else cout<<dp[(1<<n)-1]<<endl;return 0;
}