【洛谷4005】小Y和地铁(搜索)

博客围绕洛谷4005“小Y和地铁”题目展开,先提及题面,指出样例未涵盖从下绕道左、跨上再绕右到下的情况。题解将方法分类后得4种决策,两两一组影响相同,贪心选较优值剩两种方法,采用爆搜+最优性剪枝,用二进制状压计算贡献,时间复杂度O(2^{n/2})。

【洛谷4005】小Y和地铁(搜索)

题面

洛谷
有点长。

题解

首先对于需要被链接的两个点,样例中间基本上把所有的情况都给出来了。
但是还缺了一种从下面绕道左边在从整个上面跨过去在从右边绕到下面来的情况(从反过来是一样的)
然后把所有方法分类之后发现实际上只有\(4\)种决策。
\(4\)种决策中,两两一组,可以发现对于后面结果的影响是相同的,
那么只需要贪心的考虑选择两种决策的较优值。
所以只剩下两种方法了,直接爆搜+最优性剪枝,拿个二进制什么的状压一下计算贡献,
时间复杂度\(O(2^{n/2})\)

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAX 50
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
int cnt[1<<22],n,m,ans;
int a[MAX],l[MAX],r[MAX],c[MAX],b[MAX],st[MAX],lst[MAX];
void dfs(int x,int S,int tot)
{
    if(tot>=ans)return;
    if(x==m){ans=tot;return;}
    int s=cnt[st[x]&S];
    dfs(x+1,S|(1<<x),tot+min(s,b[x]-s));
    dfs(x+1,S,tot+min(c[x]-s,b[x]-c[x]+s));
}
int main()
{
    for(int Cases=read(),mx=0;Cases;--Cases)
    {
        n=read();m=0;ans=1e9;
        for(int i=mx;i<1<<(n/2);++i)cnt[i]=cnt[i>>1]+(i&1);mx=max(mx,1<<(n/2));
        for(int i=1;i<=n;++i)a[i]=read(),lst[i]=b[i]=c[i]=st[i]=0;
        for(int i=n;i;--i)
            if(!lst[a[i]])lst[a[i]]=i;
            else l[m]=i,r[m]=lst[a[i]],++m;
        reverse(&l[0],&l[m]);reverse(&r[0],&r[m]);
        for(int i=0;i<m;++i)
            for(int j=0;j<i;++j)
                if(r[j]>l[i]){++b[i];if(r[j]<r[i])st[i]|=1<<j,++c[i];}
        dfs(0,0,0);printf("%d\n",ans);
    }
    return 0;
}

转载于:https://www.cnblogs.com/cjyyb/p/9552076.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值