zoukankan      html  css  js  c++  java
  • [vijos1048]送给圣诞夜的贺卡<DFS剪枝>

    题目链接:https://www.vijos.org/p/1048

    很多人一看就想出了思路,不就是一个裸的dfs蛮。。。但是。。在n<=50的情况下,朴素会直接tle。。。。。

     

    然后我就开始剪枝,剪了很多地方,然后多过了一个点。。。。。然后我就发现我的剪枝和我的dfs打的不行

    然后我们先看看朴素的打法(打法多,我是一种非常原始的朴素算法)

     1 bool check(int x,int dep){
     2     for(int i=1;i<=dep;i++)
     3      if(map[a[i]][x]==1)return 0;
     4     return 1;
     5 }
     6 
     7 void dfs(int dep,int pos){
     8     if(dep==m+1){ans=max(ans,s);return;}
     9     if(s+tot[n]-tot[pos-1]<=ans)return;
    10     for(int i=1;i<=n,dep-1+n-i+1>=m;i++){
    11         if(vis[i]==0&&check(e[i].ord,dep-1)){
    12             vis[i]=1;
    13             a[dep]=e[i].ord;
    14             s+=val[i];
    15             dfs(dep+1,i+1);
    16             s-=val[i];
    17             a[dep]=0;
    18             vis[i]=0;
    19         }
    20     }
    21     return ;
    22 }
    View Code

     

    然后我的这个dfs本身就不够优化。。我其实可以换成不扩展深度dep,而是扩展当前的指针pos,代替我原来程序的i

    另一个优化的地方,在这个朴素的程序里面也有,就是维护一个前缀和,如果当前值的大小+后面未遍历的所有值<=我们当前的ans,就跳过

    然后就是对于是不是有矛盾的判断,我的朴素算法是邻接矩阵来暴力跑个O(n)来判断

    这个位置可以优化,我们开一个二维数组en[i][j],其中i代表初始序号为i的数,en[i][0]存这个i多少有矛盾的人,然后j就是第几个矛盾的人,e[i][j]就是和i有矛盾的第j个人的序号

    然后在判断时加一个enm[x]数组,如果enm[x]==0,说明当前x是没有敌人的,然后就把x 的所有敌人的enm[i]++,标记这些人就有敌人了。。。

    然后还剩一个优化的地方,就是排序,这个排序的主要作用是配合我们维护前缀和的剪枝,不过排序要注意排序后的序号和输入矛盾两人的序号可能不同,输入矛盾序号是按照最开始的序号来的,所以要稍微处理一下这个细节

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<queue>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<cstdlib>
     8 #define maxn 60
     9 using namespace std;
    10 
    11 int n,m,ans,s,sum,val[maxn],a[maxn],vis[maxn];
    12 int tot[maxn],en[maxn][maxn],enm[maxn]; 
    13 struct node{
    14     int v,ord;
    15 }e[maxn];
    16 
    17 int comp(const void*a,const void*b){
    18     return (*(struct node*)a).v<(*(struct node*)b).v?1:-1;
    19 }
    20 
    21 void dfs(int pos){
    22     if(pos==n+1){ans=max(ans,s);return;}
    23     if(s+tot[n]-tot[pos-1]<=ans)return;
    24     int o=e[pos].ord;
    25     if(enm[o]==0){
    26         for(int i=1;i<=en[o][0];i++)
    27             enm[en[o][i]]++;
    28         s+=e[pos].v;
    29         dfs(pos+1);
    30         s-=e[pos].v;
    31         for(int i=1;i<=en[o][0];i++)
    32             enm[en[o][i]]--;        
    33     }
    34     dfs(pos+1);
    35 }
    36 
    37 int main(){
    38     scanf("%d",&n);
    39     for(int i=1;i<=n;i++){
    40         scanf("%d",&val[i]);e[i].v=val[i];e[i].ord=i;
    41     }
    42         e[0].v=0x3f3f3f;
    43     qsort(e,n+1,sizeof(e[0]),comp);
    44     for(int i=1;i<=n;i++){
    45         tot[i]=tot[i-1]+e[i].v;
    46     }
    47     int x,y;
    48     while(scanf("%d%d",&x,&y)!=EOF){
    49         en[x][++en[x][0]]=y;
    50         en[y][++en[y][0]]=x;
    51     }
    52     dfs(1);
    53     printf("%d",ans);
    54 }
    55     
    View Code

     

     

    【总结】

    DFS的优化着手点:

    1.数据排序,加上对未来最大情况判断(本题表现为前缀和)

    2.DFS的参数不用dep(选了几个数),而用pos(正在判断第几个数)

    3.记录与自己有关系的人,不用邻接矩阵,用list[i][j]表示,list[i][0]为和自己有关系的人的个数

     

  • 相关阅读:
    ListView的删除绑定有问题
    ListView的查询绑定
    突然发现这个VSPaste插件粘贴过来的代码居然有白色背景,还只有一部分有,好纠结。。。
    IIS8中部署WCF服务出错:HTTP 错误 404.3 Not Found
    VS2012更新Update1后帮助查看器无法打开
    VS中的一些有用的小工具
    关于ASP.NET的数据绑定
    关于SQL SERVER中TSQL语句的变量
    关于ADO.NET使用中遇到的一些错误
    C#简单的多线程
  • 原文地址:https://www.cnblogs.com/Danzel-Aria233/p/7700568.html
Copyright © 2011-2022 走看看