给出一张n个点m条边的图,保证图中不存在长度大于10的简单路径
选择某一个点需要付出Ci的代价,求最小代价使得每个点都被选择,或者它相邻的点被选择
原题似乎是POI2012的某道题(夕立:poi?)
而题解的source似乎错了
这个条件显然是提示着我们要状压
但是二进制状态似乎不靠谱,我们要压三进制,表示某个点选/不选被覆盖/不选没被覆盖
然后沿着欧拉序转移就好了
看上去复杂度很不靠谱但是事实上能跑过23333
#include
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define rep(i,a) for(int i=last[a];i;i=next[i])
using namespace std;
int read() {
char ch;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
int x=ch-'0';
for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
}
void updata(int &x,int y) {
if (y<x) x=y;
}
const int N=5*1e4+5,S=6*1e4,inf=2e9;
int last[N],next[N],t[N],l;
void add(int x,int y) {
t[++l]=y;next[l]=last[x];last[x]=l;
}
int n,m,x,y,id,c[N],dep[N],three[11];
void init() {
n=read();m=read();
fo(i,1,n) c[i]=read();
fo(i,1,m) {
x=read();y=read();
add(x,y);add(y,x);
}
three[0]=1;fo(i,1,10) three[i]=three[i-1]*3;
}
int f[11][S],a[11],vis[N];
bool link[11];
void dfs(int x,int y) {
vis[x]=id;dep[x]=dep[y]+1;
rep(i,x) if (vis[t[i]]!=id) dfs(t[i],x);
}
void dp(int x,int y) {
vis[x]=id;fo(i,1,10) link[i]=0;
rep(i,x) if (dep[t[i]]x]) link[dep[t[i]]]=1;
fo(s,0,three[dep[x]]-1) f[dep[x]][s]=inf;
fo(s,0,three[dep[y]]-1) {
if(f[dep[y]][s]==inf) continue;
int ts=s;
fo(i,1,dep[y]) a[i]=ts%3,ts/=3;
bool pty=0;
fo(i,1,dep[y]) pty|=link[i]&(a[i]==2);
f[dep[x]][s+pty*three[dep[x]-1]]=f[dep[y]][s];
ts=s+2*three[dep[x]-1];
fo(i,1,dep[y]) if (link[i]&&!a[i]) ts+=three[i-1];
updata(f[dep[x]][ts],f[dep[y]][s]+c[x]);
}
rep(i,x)
if (vis[t[i]]!=id) {
dp(t[i],x);
fo(s,0,three[dep[x]]-1) {
f[dep[x]][s]=f[dep[t[i]]][s+three[dep[t[i]]-1]];
updata(f[dep[x]][s],f[dep[t[i]]][s+2*three[dep[t[i]]-1]]);
}
}
}
void solve() {
int ans=0;
fo(i,1,n)
if (!vis[i]) {
++id;dfs(i,0);
++id;dp(i,0);
ans+=min(f[1][1],f[1][2]);
}
printf("%d\n",ans);
}
int main() {
freopen("absurdity.in","r",stdin);
freopen("absurdity.out","w",stdout);
init();
solve();
return 0;
}