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

4 篇文章 0 订阅
1 篇文章 0 订阅

题面
题解
太巧妙了。。。图上还能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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值