『比赛』2016"百度之星" - 初赛(Astar Round2A) 1002

Sitting in Line
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5691
个人想法:这是我第一次感觉做状压这么难的地方,其实我并不会做这道题,因为我感觉完全没思路,我有点不敢去写,可能是我对状压理解的不够深,我听同学说可以用旅行商的状压来解决这道问题,可是我完全悟不出旅行商的道理来,然后我自己琢磨的想了想,我想出了一种自己对这道题理解的状压.实在艰辛啊…

分析:给你一堆数,有些可以和其他数字互换位置,有些却只能在固定的位置,要使得max{a1⋅a2+a2⋅a3+…+aN−1⋅aN}的值最大,这里写图片描述首先可以看到,除了1,4其他位置都是可以不可以动的的,我就想,如果我枚举每一层可以互换的位置和标记我用过了的数,那么我不就解决问题了,例如说现在 第1层我可以选择两个数字{20,50},那么如果我选择了{20},如果能用状态标记过我选择过了的数,下一层4,我就只能选择{50}了,同样道理,如果选择了{50},我下一层就只能选择{20},对于每一层,反正我都得选一个数字,我选了这个数字,我能把他标记了就好了所以我写得**dp[s][j]:s代表哪些数用了,哪些数字还没用,j就是我上一次选择的数字.**你会问为什么记录上一次的数字,你可以看到因为有些段是连续可选的,这里写图片描述
假若现在1,2层的数字是随机的,那么如果我选择第2层的时候,我并不知道前一层选择了的数字,随意我只能通过前一层枚举过的数字来递推下一层的数字.
这里写图片描述
首先我们会遇到这种情况,这时,我们递推就不需要利用上层的数字了,因为第一层已经被夹住,所以转移方程会成为dp[s|1<<1][1]加上a0a1+a1a2的值,决定过的值必须加上,同样道理还会出现
这里写图片描述
那 么第一层我就得处理成dp[s|1<<0][0]加上a0*a1的值,主要是因为后一层已经决定过了,这层就不管了,直接加上就行,其他情况也是类型的…
我的dp是先对状态预处理一下,例如第3章图的1,2层,其实直接把他的值乘起来就好了,因为值已经决定,我们不枚举这层,直接走过,可能状压有点难,直接看看代码吧–>

代码:

/* Author:GavinjouElephant
 * Title:
 * Number:
 * main meanning:
 *
 *
 *
 */

//#define OUT
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define Clear(x) memset(x,0,sizeof(x))
const int INF=0x6f6f6f6f;
int T;
int N;
int has;//初始有多少个层已经被利用
int Can[20];//这是用来表示这个位置的值是不是可选的
int Can_Value[20];//对应位置的值
int Top;//用来记录Pos的长度
int Pos[20];//表示哪层是没决定的
int State;//开始的状态
int dp[1<<16][20];
class Node
{
public:
    int x;
    int y;
}node[20];
bool cmp(const  Node &a,const Node &b)
{
    return a.y>b.y;
}
void init()
{
    memset(Can,-1,sizeof(Can));
    memset(dp,-0x6f,sizeof(dp));
    memset(Pos,0,sizeof(Pos));

}
int getx(int x)
{
    int ans=0;
    while(x)
    {
        if(x&1)ans++;
        x>>=1;
    }
    return ans;
}


int main()
{
#ifdef OUT
    freopen("coco.txt","r",stdin);
    freopen("lala.txt","w",stdout);
#endif
    scanf("%d",&T);
    int caseT=0;
    while(T--)
    {
       Top=0;
       State=0;
       has=0;
       caseT++;
       printf("Case #%d:\n",caseT);
       init();

       scanf("%d",&N);
       for(int i=0;i<N;i++)
       {
           scanf("%d%d",&node[i].x,&node[i].y);
           if(node[i].y!=-1)
           {
               has++;
               State+=(1<<node[i].y);
           }
       }
       sort(node,node+N,cmp);
      if(N==1){printf("%d\n",node[0].x);continue;}
       int index=0;
       for(int i=0;i<N;i++)
       {
           if(node[i].y!=-1)
           {
               Can[node[i].y]=0;
               Can_Value[node[i].y]=node[i].x;
               continue;
           }
           for(;index<N;index++)
           {
               if(Can[index]==-1)
               {
                  Pos[Top++]=index;
                  Can_Value[index]=node[i].x;
                  index++;
                  break;
               }
           }
       }
     //上面的一堆代码其实就是处理一下位置,因为 p是未知得,我就处理一下,p!=-1的先放对应Can里面,然后剩下的随便排就好

      //下面这一段是把那种连续层的值先加上,
       int Value=0;
       for(int j=1;j<N;j++)
       {
           if((State&(1<<j))&&(State&(1<<(j-1))))
           {
               Value+=Can_Value[j]*Can_Value[j-1];
           }
       }
       dp[State][0]=Value;

       //先预处理第一层,因为第一层递推后面层,而且判断条件和后续层不一样,所以为了少点代码就先处理了
       for(int j=0;j<N;j++)
       {
           int now=Pos[0];
           int left=now-1;
           int right=now+1;
           if(State&(1<<j))continue;

           if(now==0)
           {
               if(Can[right]==-1)
               {
                 dp[State|(1<<j)][j]=Value;//这代表下一层是可选的状态

               }
               else
               {
                 dp[State|(1<<j)][j]=Value+(Can_Value[j]*Can_Value[right]);
               }
           }
           else if(now==N-1)
           {
                dp[State|(1<<j)][j]=Value+(Can_Value[j]*Can_Value[left]);
           }
           else
           {
               if(Can[right]==-1)
               {
                   dp[State|(1<<j)][j]=Value+(Can_Value[j]*Can_Value[left]);
                  // cout<<Value<<endl;
               }
               else
               {
                   dp[State|(1<<j)][j]=Value+(Can_Value[j]*Can_Value[left])+(Can_Value[j]*Can_Value[right]);
               }
           }

       }

       for(int s=State+1;s<((1<<N)-1);s++)
       {
           int x=getx(s);
           int now=Pos[x-has];
           int left=now-1;
           int right=now+1;
           if(x==has)continue;
           for(int j=0;j<N;j++)
           {
                if(s&(1<<j))continue;
                for(int k=0;k<N;k++)
                {
                     if(dp[s][k]==-INF)continue;//如果这个状态没有其他状态递推过过来,那就不管了,
                    //这一样的对当前层进行处理,一定要注意究竟前一层是不是可选的和后一层是不是可选的;
                     if(now==N-1)
                     {
                          if(Can[left]==-1)
                          {
                              dp[s|(1<<j)][j]=max(dp[s|(1<<j)][j],dp[s][k]+Can_Value[j]*Can_Value[k]);
                          }
                          else
                          {
                              dp[s|(1<<j)][j]=max(dp[s|(1<<j)][j],dp[s][k]+Can_Value[j]*Can_Value[left]);
                          }
                     }
                     else
                     {
                        if(Can[left]==-1)
                        {
                           if(Can[right]==-1) {dp[s|(1<<j)][j]=max(dp[s|(1<<j)][j],dp[s][k]+Can_Value[j]*Can_Value[k]);}
                           else {dp[s|(1<<j)][j]=max(dp[s|(1<<j)][j],dp[s][k]+Can_Value[j]*Can_Value[k]+Can_Value[j]*Can_Value[right]);}
                        }
                        else
                        {
                           if(Can[right]==-1) {dp[s|(1<<j)][j]=max(dp[s|(1<<j)][j],dp[s][k]+Can_Value[j]*Can_Value[left]);}
                           else{dp[s|(1<<j)][j]=max(dp[s|(1<<j)][j],dp[s][k]+Can_Value[j]*Can_Value[left]+Can_Value[j]*Can_Value[right]);}
                        }
                     }

                }

           }
       }
       int ans=-INF;
       for(int j=0;j<N;j++)
       {
          ans=max(ans,dp[(1<<N)-1][j]);
       }

       printf("%d\n",ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 目标检测的定义 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具有挑战性的问题。 目标检测任务可分为两个关键的子任务,目标定位和目标分类。首先检测图像中目标的位置(目标定位),然后给出每个目标的具体类别(目标分类)。输出结果是一个边界框(称为Bounding-box,一般形式为(x1,y1,x2,y2),表示框的左上角坐标和右下角坐标),一个置信度分数(Confidence Score),表示边界框中是否包含检测对象的概率和各个类别的概率(首先得到类别概率,经过Softmax可得到类别标签)。 1.1 Two stage方法 目前主流的基于深度学习的目标检测算法主要分为两类:Two stage和One stage。Two stage方法将目标检测过程分为两个阶段。第一个阶段是 Region Proposal 生成阶段,主要用于生成潜在的目标候选框(Bounding-box proposals)。这个阶段通常使用卷积神经网络(CNN)从输入图像中提取特征,然后通过一些技巧(如选择性搜索)来生成候选框。第二个阶段是分类和位置精修阶段,将第一个阶段生成的候选框输入到另一个 CNN 中进行分类,并根据分类结果对候选框的位置进行微调。Two stage 方法的优点是准确度较高,缺点是速度相对较慢。 常见Tow stage目标检测算法有:R-CNN系列、SPPNet等。 1.2 One stage方法 One stage方法直接利用模型提取特征值,并利用这些特征值进行目标的分类和定位,不需要生成Region Proposal。这种方法的优点是速度快,因为省略了Region Proposal生成的过程。One stage方法的缺点是准确度相对较低,因为它没有对潜在的目标进行预先筛选。 常见的One stage目标检测算法有:YOLO系列、SSD系列和RetinaNet等。 2 常见名词解释 2.1 NMS(Non-Maximum Suppression) 目标检测模型一般会给出目标的多个预测边界框,对成百上千的预测边界框都进行调整肯定是不可行的,需要对这些结果先进行一个大体的挑选。NMS称为非极大值抑制,作用是从众多预测边界框中挑选出最具代表性的结果,这样可以加快算法效率,其主要流程如下: 设定一个置信度分数阈值,将置信度分数小于阈值的直接过滤掉 将剩下框的置信度分数从大到小排序,选中值最大的框 遍历其余的框,如果和当前框的重叠面积(IOU)大于设定的阈值(一般为0.7),就将框删除(超过设定阈值,认为两个框的里面的物体属于同一个类别) 从未处理的框中继续选一个置信度分数最大的,重复上述过程,直至所有框处理完毕 2.2 IoU(Intersection over Union) 定义了两个边界框的重叠度,当预测边界框和真实边界框差异很小时,或重叠度很大时,表示模型产生的预测边界框很准确。边界框A、B的IOU计算公式为: 2.3 mAP(mean Average Precision) mAP即均值平均精度,是评估目标检测模型效果的最重要指标,这个值介于0到1之间,且越大越好。mAP是AP(Average Precision)的平均值,那么首先需要了解AP的概念。想要了解AP的概念,还要首先了解目标检测中Precision和Recall的概念。 首先我们设置置信度阈值(Confidence Threshold)和IoU阈值(一般设置为0.5,也会衡量0.75以及0.9的mAP值): 当一个预测边界框被认为是True Positive(TP)时,需要同时满足下面三个条件: Confidence Score > Confidence Threshold 预测类别匹配真实值(Ground truth)的类别 预测边界框的IoU大于设定的IoU阈值 不满足条件2或条件3,则认为是False Positive(FP)。当对应同一个真值有多个预测结果时,只有最高置信度分数的预测结果被认为是True Positive,其余被认为是False Positive。 Precision和Recall的概念如下图所示: Precision表示TP与预测边界框数量的比值 Recall表示TP与真实边界框数量的比值 改变不同的置信度阈值,可以获得多组Precision和Recall,Recall放X轴,Precision放Y轴,可以画出一个Precision-Recall曲线,简称P-R
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值