zoukankan      html  css  js  c++  java
  • 【NOI2003】智破连环阵

    题目描述

    B国在耗资百亿元之后终于研究出了新式武器——连环阵(Zenith Protected Linked Hybrid Zone)。传说中,连环阵是一种永不停滞的自发性智能武器。但经过A国间谍的侦察发现,连环阵其实是由M个编号为1,2,…,M的独立武器组成的。最 初,1号武器发挥着攻击作用,其他武器都处在无敌自卫状态。以后,一旦第i(1<=i< M)号武器被消灭,1秒种以后第i+1号武器就自动从无敌自卫状态变成攻击状态。当第M号武器被消灭以后,这个造价昂贵的连环阵就被摧毁了。

    为了彻底打击B国科学家,A国军事部长打算用最廉价的武器——炸弹来消灭连环阵。经过长时间的精密探测,A国科学家们掌握了连环阵中M个武器的平面 坐标,然后确定了n个炸弹的平面坐标并且安放了炸弹。每个炸弹持续爆炸时间为5分钟。在引爆时间内,每枚炸弹都可以在瞬间消灭离它平面距离不超过k的、处 在攻击状态的B国武器。和连环阵类似,最初a1号炸弹持续引爆5分钟时间,然后a2号炸弹持续引爆5分钟时间,接着a3号炸弹引爆……以此类推,直到连环 阵被摧毁。

    显然,不同的序列a1、a2、a3...消灭连环阵的效果也不同。好的序列可以在仅使用较少炸弹的情况下就将连环阵摧毁;坏的序列可能在使用完所有 炸弹后仍无法将连环阵摧毁。现在,请你决定一个最优序列a1、a2、a3…使得在第ax号炸弹引爆的时间内连环阵被摧毁。这里的x应当尽量小。

    输入输出格式

    输入格式:

    第一行包含三个整数:M、n和k(1<=M, n<=100,1<=k<=1000),分别表示B国连环阵由M个武器组成,A国有n个炸弹可以使用,炸弹攻击范围为k。以下M行,每 行由一对整数xi,yi(0<=xi,yi<=10000)组成,表示第i(1<=i<=M)号武器的平面坐标。再接下来n行, 每行由一对整数ui,vi(0<=ui,vi<=10000)组成,表示第i(1<=i<=n)号炸弹的平面坐标。输入数据保证 随机、无误、并且必然有解。

    输出格式:

    一行包含一个整数x,表示实际使用的炸弹数

    输入输出样例

    输入样例#1:
    4 3 6
    0 6
    6 6
    6 0
    0 0
    1 5
    0 3
    1 1
    0 0
    
    输出样例#1:
    2


    需要将B国的武器分为连续的k,并且这k段中的每一段都能被某个大炮攻击到.

    然后就可以搜索怎么分段,然后用二分图匹配判断.

    Can[s][t][i] 表示A国大炮i能否炸掉B[s,t]中的所有武器,这个递推判断一下就好了.

    MaxT[s][i]表示大炮is开始打,可以打到的最大编号的武器的编号.初值MaxT[s][i]=s-1.这个简单DP一下.

    Dis[i]表示如果A国大炮可以重复使用,打掉从im的武器至少需要的大炮的数量.这个用
    DP求出,状态转移方程为:dis[i]=1+dis[j]其中,j=max(MaxT[i][k]).

    这个东西用来最优性剪枝,若当前已用的大炮+dis[当前已经攻击了的武器+1]>最优解则剪枝.

    我们在枚举区间长度时,可以先用O(n^2)的广搜求出最大可攻击到的武器编号maxL,显然编号小于等于maxL的武器都可以被攻击到.

    怎么求maxL?

    设二分图的A数组表示武器区间,B数组表示大炮.

    用广搜的方法,若某个点i为未匹配点,那么可以使用;若某个点i为匹配点,且存在一条从未匹配点的交错路,则这个点也是可以使用的,因为这条匹配边增广之后就不是匹配边了.每次出队的时候更新maxL.

    然后连边,增广,搜索下一个区间.

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<string>
     6 #include<algorithm>
     7 #include<map>
     8 #include<complex>
     9 #include<queue>
    10 #include<stack>
    11 #include<cmath>
    12 #include<set>
    13 #include<vector>
    14 using namespace std;
    15 int reach[110][110],n,m,x1[110],x2[110],Y1[110],y2[110],a[110],b[110];
    16 bool can[110][110][110],g[110][110],vis[110];
    17 int MaxT[110][110],dis[110],ans=1999999999;//MaxT[s][i]炸弹i从s开始可炸到的最大编号.
    18 void prepare(){
    19   for(int s=1;s<=m;s++){
    20     for(int i=1;i<=n;i++)
    21       can[s][s][i]=reach[s][i];
    22     for(int t=s+1;t<=m;t++)
    23       for(int i=1;i<=n;i++)
    24     can[s][t][i]=can[s][t-1][i] && reach[t][i];
    25     for(int i=1;i<=n;i++){
    26       MaxT[s][i]=s-1;
    27       for(int t=s;t<=m;t++)
    28         if(can[s][t][i])
    29           MaxT[s][i]=t;
    30     }
    31   }
    32   dis[m+1]=0;
    33   for(int s=m;s>=1;s--){
    34     int t=s-1;
    35     for(int i=1;i<=n;i++)
    36       if (MaxT[s][i]>t)
    37     t=MaxT[s][i];
    38     dis[s]=1+dis[t+1];
    39   }
    40 }
    41 bool find(int v){//匈牙利算法
    42   for(int i=1;i<=n;i++)
    43     if(g[v][i] && !vis[i]){
    44       vis[i]=1;
    45       if(b[i]==0 || find(b[i])){
    46     a[v]=i;
    47     b[i]=v;
    48     return 1;
    49       }
    50     }
    51   return 0;
    52 }
    53 void search(int now,int s){
    54   if(now+dis[s]>=ans) return;
    55   if(s==m+1) {ans=now;return;}
    56   int tmpa[110],tmpb[110];
    57   queue<int>Q;
    58   memset(vis,0,sizeof(vis));
    59   int maxL=s-1;
    60   for(int i=1;i<=n;i++)
    61     if(b[i]==0) vis[i]=1,Q.push(i);
    62   while(!Q.empty()){
    63     int u=Q.front();
    64     Q.pop();
    65     maxL=max(maxL,MaxT[s][u]);
    66     for(int i=1;i<=now;i++)
    67       if(g[i][u] && !vis[a[i]])
    68     vis[a[i]]=1,Q.push(a[i]);
    69   }
    70   memcpy(tmpa,a,sizeof(a));memcpy(tmpb,b,sizeof(b));
    71   memset(vis,0,sizeof(vis));
    72   now++;
    73   for(int i=1;i<=n;i++)
    74     g[now][i]=can[s][maxL][i];
    75   find(now);//增广
    76   for(int t=maxL;t>=s;t--){
    77     for(int i=1;i<=n;i++)
    78       g[now][i]=can[s][t][i];
    79     search(now,t+1);
    80   }
    81   memcpy(a,tmpa,sizeof(a));memcpy(b,tmpb,sizeof(b));
    82 }
    83 int main(){
    84   int R;//m个武器,n个炸弹
    85   scanf("%d%d%d",&m,&n,&R);
    86   for(int i=1;i<=m;i++) scanf("%d%d",&x1[i],&Y1[i]);
    87   for(int i=1;i<=n;i++) scanf("%d%d",&x2[i],&y2[i]);
    88   for(int i=1;i<=m;i++)
    89     for(int j=1;j<=n;j++)
    90       reach[i][j]=((x1[i]-x2[j])*(x1[i]-x2[j])+(Y1[i]-y2[j])*(Y1[i]-y2[j])<=R*R);
    91   prepare();
    92   search(0,1);
    93   printf("%d",ans);
    94   return 0;
    95 }
  • 相关阅读:
    外文翻译 《How we decide》多巴胺的预言 第三节
    外文翻译 《How we decide》多巴胺的预言 第二节
    WPF学习12:基于MVVM Light 制作图形编辑工具(3)
    外文翻译 《How we decide》多巴胺的预言 第一节
    xcode上真机调试iphone4s出现“There was an internal API error.”解决方案
    cocos2d-x v2.2 IOS工程支持64-bit 遇坑记录
    简单优化:Zipalign
    Error: could not open `C:Javajre7libi386jvm.cfg
    【ios开发之疑难杂症】xcode运行出现SpringBoard 无法启动应用程序(错误:7)
    java IntelliJ IDEA 13 注册码 IDEA序列号 License Key
  • 原文地址:https://www.cnblogs.com/pantakill/p/7130187.html
Copyright © 2011-2022 走看看