题意给一个数组
让从中选出尽可能多的数字,他们之间两两不存在整除关系
这题目貌似正经做法应该是偏序集的Dilworth定理和最小路径覆盖
但是这题DancingLinksX甚至DFS甚至直接for循环暴力都可以过……
以下1个105ms的hdu上考下来的暴力
#include
#include
#include
#include
#include
#include
#include
#include
最小路径覆盖和DancingLinksX都可以达到0秒
而且总感觉做最长链的过程好像和搜索的效率……
这里留一个坑等仔细研究了图论的坑再来填吧
其实暴力for可以过dfs可以过
DancingLinkX是肯定可以过得……
因为dfs或者for的过程都是选一个第一个选的数字
然后把可以互相整除的点都删掉
再在后面选,如此重复
DancingLinkX的过程其实就是省略了找哪些点需要删除
因为选了一行之后,会把所有对应的列删掉(就是互相整除的数)
比如2 3 6 这3个数
那么生成的 2的行 对应2 6的列是1
3的行 对应3 6的列是1
6的行 对应 2 3 6的列是1
如果选2行 那么会去掉2和6的列
那么就剩下一个3的列 此时会选3的行或者6的行意味都是选一个3
(这里特别的,选3选6对于个数没有区别,但是如果输出结果的话可能会有问题)
如果开始选3与选2类似
如果开始选6那么所有的行都会去掉,
意思如果选了6那么最大的不能互相整除的集合就只能有这一个数。
然后这题另一个比较特殊的点就是要用DancingLinksX求一个最大深度
因此A*的函数也可以改改
#include
#include
#include
using namespace std;
typedef long long LL;
const int M=1e3+5;
const int MN=M;
const int MM=M;
const int MNN=MN*MM+MM; //最大点数
LL nu[M];
struct DLX
{
int n,m,si;//n行数m列数si目前有的节点数
//十字链表组成部分
int U[MNN],D[MNN],L[MNN],R[MNN],Row[MNN],Col[MNN];
//第i个结点的U向上指针D下L左R右,所在位置Row行Col列
int H[MN],S[MM]; //记录行的选择情况和列的覆盖情况
int ansd,ans[MN];//ansd最小步数,需要初始化
void init(int _n,int _m) //初始化空表
{
n=_n;
m=_m;
for(int i=0;i<=m;i++) //初始化第一横行(表头)
{
S[i]=0;
U[i]=D[i]=i; //目前纵向的链是空的
L[i]=i-1;
R[i]=i+1; //横向的连起来
}
R[m]=0;L[0]=m;
si=m; //目前用了前0~m个结点
for(int i=1;i<=n;i++)
H[i]=-1;
}
void link(int r,int c) //插入点(r,c)
{
++S[Col[++si]=c]; //si++;Col[si]=c;S[c]++;
Row[si]=r;
D[si]=D[c];
U[D[c]]=si;
U[si]=c;
D[c]=si;
if(H[r]<0)
H[r]=L[si]=R[si]=si;
else
{
R[si]=R[H[r]];
L[R[H[r]]]=si;
L[si]=H[r];
R[H[r]]=si;
}
}
void remove(int c)
{
for(int i=D[c];i!= c;i= D[i])
L[R[i]]=L[i],R[L[i]]=R[i];
}
void resume(int c)
{
for(int i=U[c];i!= c;i=U[i])
L[R[i]]=R[L[i]]=i;
}
int h() //估值
{
int ret=0;
for(int c=R[0];c!=0;c=R[c])
ret++;
return ret;
}
void dance(int d)
{
if(d+h()<=ansd) //利用A*优化
return;
if(R[0]==0)
{
// cout<
如果A*的函数h还是用原来的
bool v[MNN];
int h() //估值
{
int ret=0;
for(int c=R[0];c!=0;c=R[c])
v[c]=1;
for(int c=R[0];c!=0;c=R[c])
if(v[c])
{
ret++;
v[c]=0;
for(int i=D[c];i!=c;i=D[i])
for(int j=R[i];j!=i;j=R[j])
v[Col[j]]=0;
}
return ret;
}
时间会变成15ms……