GYM101002 A

题意:
有n个物品,m个商店。每个物品会在两个商店x,y中按不同价钱p,q出售。现在最多能去k个商店,问每个物品买一件最少要多少钱。无解输出-1。
1<=x,y<=n<=100
k<=m<=40
p,q<=10^7

#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<iostream>
#define LL long long
#define N 110
#define M 20
#define ms ((1<<20)-1)
#define lowbit(x) (x&(-x))
using namespace std;
int n,m,k,ss,cnt[1<<M],id[1<<M],ans,f[N][2],g[N][2];
LL e[N];
bool must[N];
void pre()
{
    for(int i=1;i<=ms;i++) cnt[i]=cnt[i-lowbit(i)]+1;
    for(int i=0;i<M;i++) id[1<<i]=i;
}
LL sum(LL x,LL y)
{
    return x|y;
}
LL dif(LL x,LL y)
{
    x=ss^x;
    x|=y;
    x=ss^x;
    return x;
}
int count(LL s)
{
    return cnt[s&ms]+cnt[s>>M];
}
int find(LL s)
{
    if(s<(1ll<<M)) return id[s];
    return 20+id[s>>M];
}
void solve(LL s)
{
    int tmp=0;
    for(int i=1;i<=n;i++)
        if(s&(1ll<<f[i][0])) tmp+=f[i][1];
        else if(s&(1ll<<g[i][0])) tmp+=g[i][1];
        else return;
    if(ans==-1 || ans>tmp) ans=tmp;
}
void dfs(LL chosen,LL alive)
{
    int siz=count(chosen);
    if(siz>k) return;
    if(siz==k || alive==0) {solve(chosen);return;}
    LL new_chosen,new_alive;int x=find(lowbit(alive));
    new_chosen=chosen;new_alive=alive;
    new_chosen=sum(new_chosen,1ll<<x);
    new_alive=dif(new_alive,1ll<<x);
    dfs(new_chosen,new_alive);

    new_chosen=chosen;new_alive=alive;
    new_alive=dif(new_alive,1ll<<x);
    LL r=e[x]&new_alive;
    new_chosen=sum(new_chosen,r);
    new_alive=dif(new_alive,r);
    dfs(new_chosen,new_alive);
}
int main()
{
    pre();
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
    {
        int x,y,p,q;scanf("%d%d%d%d",&x,&p,&y,&q);
        if(p>q) swap(x,y),swap(p,q);
        x--;y--;
        e[x]|=1ll<<y;e[y]|=1ll<<x;
        f[i][0]=x;f[i][1]=p;
        g[i][0]=y;g[i][1]=q;
        if(x==y) must[x]=1;
    }
    LL chosen=0,alive=(1ll<<m)-1;
    ss=(1ll<<m)-1;
    for(int i=0;i<m;i++) 
        if(must[i]) chosen=sum(chosen,1ll<<i),alive=dif(alive,1ll<<i);
        else if(e[i]==0) alive=dif(alive,1ll<<i);
    ans=-1;
    dfs(chosen,alive);
    printf("%d\n",ans);
    return 0; 
}

题解:
这个范围很像折半,但根本没办法合并啊。。
于是膜了题解,发现了一个新套路。。
把商店看成点,物品看成边,然后搜搜搜
设T(n)为决策n个点的复杂度
拿出一个还未决策的点x
如果要选x,直接递归,复杂度T(n-1)
如果不选x,那么和x相邻的点全部都要选,复杂度<=T(n-2)
于是就有T(n)=T(n-1)+T(n-2)
要处理掉自环和孤立的点,否则无法保证第二部分的T(n-2)。。
n=40还是很资磁的,要用位运算优化。。
注意点覆盖问题,有个套路,搜的时候如果一个点不选,那相邻点都要选

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值