题意:
有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还是很资磁的,要用位运算优化。。
注意点覆盖问题,有个套路,搜的时候如果一个点不选,那相邻点都要选