第九周经验总结

目录

1 DFS(深搜)

2.贪心问题

3.寄邮件


1 DFS(深搜)

类似一个多叉树,遍历所有的路径进行搜索,它运用了回溯,保存这次的位置并深入搜索,都搜索完便回溯回来,搜下一个位置,直到把所有都搜一遍,返回所有的最优解,多用到递归来实现

例题:素数环:输入正整数n,把整数1,2,3,.....n组成一个环,使得相邻两个整数之和均为素数。输出时从整数1开始逆时针排列。同一个环应恰好只输出一次。n<=16

代码实现

#include <stdio.h>
#include <stdlib.h>
int used[17],a[17];
int prime(int n)
{
    int i;
    for(i=2;i<n/2;i++)
    if(n%i==0)return 0;
    return 1;
}
int dfs(int count,int n)
{
    int i;
    if(count==n&&prime(a[1]+a[n])==1)
    {
        for(i=1;i<=n;i++)printf("%d ",a[i]);
        printf("\n");
        return 0;
    }
    for(i=2;i<=n;i++)
    {
        if(used[i]==0&&prime(i+a[count])==1)
        {   
            a[count+1]=i;
            used[i]=1;
            dfs(count+1,n);
            used[i]=0;
        }
    }
}
int main()
{
    int n;
    memset(a,0,sizeof(a));
    memset(used,0,sizeof(used));
    used[1]=1;
    a[1]=1;
    scanf("%d",&n);
    if(n%2==1)return;
    dfs(1,n);
    return 0;
}

代码实现思路:创建一个uesd数组,来记录1-16之间的数字有没有被使用,1为使用,0为未使用。在遍历的过程使用的used[i]赋值为1,在遍历的时候如果不满足素数环的条件,则回溯回上一层,把此条线路使用过的数变回0,开始下一个节点的搜索,如果dfs遍历到了最后一个节点且满足最后一个节点与1相加为素数则输出这条遍历线路上的数据,一直这样下去,直到搜索完所有可能,得出所有的解;此方法类似于树的遍历。

2.贪心问题

直接上例题,这个困扰了我好久

周老师的区间问题:周老师无聊时乱写了 n 个区间,但处女座的他随后又想将 n 个区间整理合并,但他发现区间太多了,于是他想请你帮帮他

代码实现

#include"stdio.h"
#include"string.h"
#include<stdlib.h>
typedef struct
{
    long long left;
    long long right;
}qvjian;
int cmp(const void *a,const void *b)
{
    qvjian *aa=(Region *)a;
    qvjian *bb=(Region *)b;
    if(aa->left>bb->left)return 1;
    else if(aa->left==bb->left)
    if(aa->right>bb->right)return 1;
    return 0;
}
int main()
{
    int N;
    long long i,j,k;
    qvjian a[15001],T;
    while(~scanf("%d",&N))
    {
        for(i=0; i<N; i++)
            scanf("%lld%lld",&a[i].left,&a[i].right);

        qsort(a,N,sizeof(a[0]),cmp);
        j=0;
        for(i=1; i<N; i++)
        {
            if(a[i].left<=a[j].right)
            {
                if(a[j].right<=a[i].right)
                    a[j].right=a[i].right;
                continue;
            }
            else
            {
                j++;
                a[j]=a[i];
            }
        }
        printf("%lld\n",j+1);
        for(i=0; i<=j; i++)
            printf("%lld %lld\n",a[i].left,a[i].right);
    }
}

 解题思路:我做这个题的基本思路是先排序,然后再合并。具体的来说呢,就是先按left(也就是题中的s)排序,大的left放后面。如果left相等,那么就将right排序。大的right放后面。
排序后,依次遍历,如果前一个区间的right大于后一个区间的left,那么他们可合并;此题也是基本的贪心思路中的区间合并问题;

为什么一直错:我之前一直尝试在原来的结构体数组上做文章,我把被合并的区间的left赋值为-1,后面输出的时候检测到left为-1就不输出;但是提交一直出错(自己测试的是对的,我也不知道错哪0.0);后面换了一种思路,先设j为第一个区间a[0],i从第二个区间开始依次往后遍历,如果可以合并,就把a[i]合并到a[j],如果不能合并,那就说吧 a[j]现在是一个独立区间,没有与任何区间重合了,然后j++一次,下一个a[j]存储下第一个没有与上一个区间合并的区间,i又开始遍历,这种操作直到i遍历到最后一个区间,区间合并就完成了,此时(j+1)的值就是有多少个区间(因为j从0开始,所以+1),再用一个循环把a[0]到a[j]的区间全部打印出来,此题就解决了。

3.寄邮件

题目:小璐有一群笔友,有一天他们跟小璐约定好去互相寄邮件,每个人只能寄一封邮件,也只能收一封信,寄给这些笔友或者是小璐,小璐也要寄,当然了不能自己寄给自己,那么小璐想知道有多少种不同的寄邮件方式,对于这等问题,小璐早就知道了答案,所以他要来考考你,那么就交给你了

代码实现:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    long long int a[21]={0},flag=1,i;
    for(i=1;i<=20;i++)
    {
        a[i]=(i+1)*a[i-1]+flag;
        flag*=-1;
    }
    int t,n;
    scanf("%d",&t);
    for(i=0;i<t;i++)
    {
        scanf("%d",&n);
        printf("%lld\n",a[n]);
    }
    return 0;
}

代码实现思路:最开始想采用bfs来解出此题,但是会出现严重的时间超限。后来利用bfs得出来的一部分结果来寻找规律,得出了 a[i]=(i+1)*a[i-1]+flag;当i为奇数时flag=1,为偶数flag=-1;用这个公式将数组a填满,当输入n时输出 a[n]即可;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值