HDU_3335_Divisibility(DancingLinksX重复覆盖||dfs||暴力)

版权声明:本文为博主原创文章。转载请注明作者,并用链接给出出处。 https://blog.csdn.net/baidu_29410909/article/details/51295392

Divisibility

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1861    Accepted Submission(s): 721


Problem Description
As we know,the fzu AekdyCoin is famous of math,especially in the field of number theory.So,many people call him "the descendant of Chen Jingrun",which brings him a good reputation.
AekdyCoin also plays an important role in the ACM_DIY group,many people always ask him questions about number theory.One day,all members urged him to conduct a lesson in the group.The rookie daizhenyang is extremely weak at math,so he is delighted.
However,when AekdyCoin tells us "As we know, some numbers have interesting property. For example, any even number has the property that could be divided by 2.",daizhenyang got confused,for he don't have the concept of divisibility.He asks other people for help,first,he randomizely writes some positive integer numbers,then you have to pick some numbers from the group,the only constraint is that if you choose number a,you can't choose a number divides a or a number divided by a.(to illustrate the concept of divisibility),and you have to choose as many numbers as you can.
Poor daizhenyang does well in neither math nor programming.The responsibility comes to you!
 

Input
An integer t,indicating the number of testcases,
For every case, first a number n indicating daizhenyang has writen n numbers(n<=1000),then n numbers,all in the range of (1...2^63-1).
 

Output
The most number you can choose.
 

Sample Input
1 3 1 2 3
 

Sample Output
2 Hint: If we choose 2 and 3,one is not divisible by the other,which is the most number you can choose.
 

Author
DaiZhenyang@BUPT
 

Source
 

Recommend
lcy



题意给一个数组

让从中选出尽可能多的数字,他们之间两两不存在整除关系


这题目貌似正经做法应该是偏序集的Dilworth定理和最小路径覆盖

但是这题DancingLinksX甚至DFS甚至直接for循环暴力都可以过……

以下1个105ms的hdu上考下来的暴力

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;
__int64 tm[1006];
__int64 vis[1006];
__int64 tol[1006];
 int max(int a,int b)
 {return a<b?b:a;}
int main()
{
	__int64 t;
	scanf("%I64d",&t);
	__int64 i,j,k;
	__int64 n;
	while(t--)
	{
		scanf("%I64d",&n);
		for (i=1;i<=n;i++)
		{
			scanf("%I64d",&tm[i]);
		}
		sort(tm+1,tm+1+n);

		for (i=1;i<=n;i++)	//假如选了第i个
		{
			tol[i]=1;
			memset(vis,0,sizeof(vis));
				for(j=i+1;j<=n;j++)
				{
					if (vis[j]|| tm[j]%tm[i]==0 )  //与第i个冲突的就不能选
						continue;
					for (k=j+1;k<=n;k++)
					{
						if (tm[k]%tm[j]==0)   //j与i不冲突,选了j,现在要把与j冲突的都删掉
							vis[k]=1;

					}
					tol[i]++; //可以选第j个,那么选第i个的方案最后答案会加1
				}
		}
		__int64 ans=tol[1];
		for (i=1;i<=n;i++)
			ans=max(tol[i],ans);
		printf("%I64d\n",ans);
	}
	return 0;
}


最小路径覆盖和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 <iostream>
#include <stdio.h>
#include <string.h>
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<<d<<endl;
//            for(int i=0;i<d;i++)
//                cout<<ans[i]<<" ";
//            cout<<endl;
            if(ansd<d)
                ansd=d;
            return;
        }
        int c=R[0];
        for(int i=R[0];i!=0;i=R[i])
            if(S[i]<S[c])
                c=i;
        for(int i=D[c];i!=c;i=D[i])
        {
            //ans[d]=Row[i];
            remove(i);
            for(int j=R[i];j!=i;j=R[j])
                remove(j);
            dance(d+1);
            for(int j=L[i];j!=i;j=L[j])
                resume(j);
            resume(i);
        }
    }
}dlx;

int main()
{
    int t;
    int n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%I64d",&nu[i]);
        dlx.init(n,n);
        for(int i=1;i<=n;i++)
        {
            dlx.link(i,i);           //link一个点两次是会出bug的……
            for(int j=i+1;j<=n;j++)
                if(nu[i]%nu[j]==0||nu[j]%nu[i]==0)
                {
                    dlx.link(i,j);
                    dlx.link(j,i);
                }
        }
        dlx.ansd=0;
        dlx.dance(0);
        printf("%d\n",dlx.ansd);
    }
    return 0;
}
如果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……

阅读更多
换一批

没有更多推荐了,返回首页