【NOIP2017提高A组冲刺11.1】荒诞

来源:互联网 发布:js顶部滑动菜单栏 编辑:程序博客网 时间:2024/05/16 04:40

Description

给出一张n个点m条边的图,保证图中不存在长度大于10的简单路径
选择某一个点需要付出Ci的代价,求最小代价使得每个点都被选择,或者它相邻的点被选择

Solution

原题似乎是POI2012的某道题(夕立:poi?)
而题解的source似乎错了
这个条件显然是提示着我们要状压
但是二进制状态似乎不靠谱,我们要压三进制,表示某个点选/不选被覆盖/不选没被覆盖
然后沿着欧拉序转移就好了
看上去复杂度很不靠谱但是事实上能跑过23333

Code

#include <cstdio>#include <cstring>#include <algorithm>#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]]<dep[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;}
原创粉丝点击