P4934 礼物---------------拓扑图,优化建边。

本文探讨了一种礼物分配问题,通过算法优化实现礼物在不同箱子中的合理分配,避免魔力值冲突,旨在寻找最少的箱子数量及具体分配方案。文章详细介绍了输入输出格式,提供了代码示例,并附带了样例数据。

题目描述

__stdcall决定给你n个礼物,每个礼物有一个魔力值ai。这些礼物的魔力值都是独一无二的,两两互不相同。这些礼物都有着神奇的魔力,如果两个礼物 i,j的魔力值满足 ai&ajmin(ai,aj) ,那么这两个礼物的魔力将会相互抵消,因此它们不能放在一个箱子里。这里的 &是按位与运算符,如果你对这一运算不够了解,请参考:https://baike.baidu.com/item/%E6%8C%89%E4%BD%8D%E4%B8%8E/9601818?fr=aladdin

作为发礼物苦力的ljt12138的箱子并不多,不过幸运的是,每个箱子都足够大。现在他请求你帮助他合理分配,用尽可能少的箱子装下所有礼物。换言之,使得每个礼物都被恰好装入一个箱子中,且同一个箱子中的礼物魔力不会相互抵消。如果有多种合法的方案,你只需要给出任意一种。

ljt12138十分善良,如果你只能求出所需要的箱子数,也可以获得该测试点60%的分数,关于这一点,请参考下面的提示与说明。

输入输出格式

输入格式:

 

  • 第一行两个数 n和k,n为礼物总数,k为一个参数,方便你进行计算。
  • 第二行 n个两两不同的数ai,满足0ai<2k,表示礼物的魔力值。

 

输出格式:

 

  • 第一行输出一个数。如果你不希望输出方案,请输出0;如果你希望输出方案,请输出1。如果你在这一行输出了不符合要求的信息,将被判为 WA。
  • 第二行一个数 m,表示你将礼物装到了m个箱子里。
  • 如果你在第一行输出了 1,接下来m行,每行表示一个箱子:首先一个数 si,表示当前箱子中礼物的个数;接下来 si个数,表示当前子集。

 

输入输出样例

输入样例#1:
5 3
0 4 7 1 6 
输出样例#1:
1
4
1 0
2 1 4
1 6
1 7 

说明

附加样例:

你可以在 https://pan.baidu.com/s/1A8_ZA4yXXi5y6771x9JKUw 下载附加样例。

关于输出方案:

  • 如果你在第一行输出了 0,而正确回答了最小所需的箱子数,将获得测试点60%的分数。
  • 如果你在第一行输出了 1,正确回答了最小所需的箱子数,但没有给出正确的方案,也将获得该测试点60%的分数。
  • 如果你没有正确回答最小所需的箱子数,将不会获得该测试点的分数。
  • 请选手注意,如果你未按照上述格式输出答案,将无法获得任何分数。

数据 n,k的关系由下面的表格给出:

数据编号nnkk
115533
226633
33771010
44881010
55161677
66171788
77171799
8817172020
99200020001717
1010250025001818
1111300030001919
1212300030002020
131325000250001515
141425000250001515
151550000500001616
161650000500001616
17172500002500001818
18185000005000001919
1919100000010000002020
2020100000010000002020

 


 

一句话题解:偏序集最小反链覆盖等于最长链,优化建图。

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int siz=2000050;
 4 int n,m,a[siz],t;
 5 int dis[siz];
 6 bool vis[siz];
 7 int head[siz],nex[siz],tot[siz];
 8 vector <int > s[20];
 9 void add(int x,int y)
10 {
11     ++tot[x];
12     nex[y]=head[x];
13     head[x]=y;
14 }
15 int main()
16 {
17     scanf("%d%d",&n,&m);
18     t=(1<<m)-1;
19     for(int i=0;i<n;++i)
20     {
21         scanf("%d",&a[i]);
22         vis[a[i]]=true;
23     }
24     for(int i=t;i>=0;--i)
25     {
26         if(vis[i])
27             ++dis[i];
28         for(int j=1;j<t;j<<=1)
29             if(i&j)
30                 dis[i^j]=max(dis[i^j],dis[i]);
31     }
32     for(int i=0;i<=t;++i)
33         if(vis[i])
34             s[dis[i]].push_back(i);
35     printf("%d\n%d",1,dis[0]);
36     for(int i=dis[0];i>=1;--i)
37     {
38         int tmp=s[i].size();
39         printf("\n%d",tmp);
40         for(int j=0;j<tmp;++j)
41             printf(" %d",s[i][j]);
42             
43     }
44     return 0;
45 }
代码

 

转载于:https://www.cnblogs.com/wyher/p/9826754.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值