[2017纪中11-1]荒诞 欧拉序+状压DP

来源:互联网 发布:java文件读写 编辑:程序博客网 时间:2024/05/21 19:38

题面
题解
太巧妙了。。。图上还能DP。。。
代码:

#include<iostream>#include<cstdio>#include<cstring>#define chkmin(a,b) a=min(a,b)using namespace std;const int maxn=100010;int n,m,c[maxn],d[maxn],f[12][60000],ans=0,mi[12];struct edge{    int t;    edge *next;}*con[maxn];int T(int s,int w){    return s/mi[w]%3;}int mx(int a,int b,int d){    for(int i=0;i<=d;i++)    {        int ta=T(a,i),tb=T(b,i);        if(tb>ta) a+=(tb-ta)*mi[i];    }    return a;   }bool lk(int a,int b,int d){    for(int i=0;i<=d;i++)        if(T(a,i)==1&&T(b,i)==2) return 1;    return 0;   }void ins(int x,int y){    edge *p=new edge;    p->t=y;    p->next=con[x];    con[x]=p;}void dfs(int v){    int fff=0,dv=d[v];    memset(f[dv],0x3f,sizeof(int)*mi[dv+1]);    for(edge *p=con[v];p;p=p->next)        if(d[p->t]!=-1)  fff+=mi[d[p->t]];    for(int s=0;s<=mi[dv]-1;s++)    {        int fas=((dv==0)?0:f[dv-1][s]);        if(fas<0x3f3f3f3f)        {            if(lk(fff,s,dv-1)) f[dv][s+mi[dv]]=fas;            else f[dv][s]=fas;            chkmin(f[dv][mx(fff,s,dv-1)+(mi[dv]<<1)],fas+c[v]);         }    }                   for(edge *p=con[v];p;p=p->next)        if(d[p->t]==-1)            d[p->t]=dv+1,dfs(p->t);    if(dv!=0)        for(int s=0;s<=(mi[dv]-1);s++)            f[dv-1][s]=min(f[dv][s+mi[dv]],f[dv][s+(mi[dv]<<1)]);}int main(){    mi[0]=1;    for(int i=1;i<=10;i++)        mi[i]=mi[i-1]*3;    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)        scanf("%d",&c[i]);    for(int i=1;i<=m;i++)    {        int x,y;        scanf("%d%d",&x,&y);        ins(x,y);        ins(y,x);    }    memset(d,-1,sizeof(d));    for(int i=1;i<=n;i++)        if(d[i]==-1)         {            d[i]=0;            dfs(i);            ans+=min(f[0][1],f[0][2]);        }    printf("%d",ans);       return 0;}