codeforces 555B Case of Fugitive

题目连接:

  http://codeforces.com/problemset/problem/555/B

题目大意:

  有n个岛屿(岛屿在一列上,可以看做是线性的,用来描述岛屿位置的是起点与终点),m个桥,给出每个岛屿的位置和桥的长度,问是否可以把n个岛屿连起来?

解题思路: 

  排序+贪心,对于n个岛屿,相邻的两个之间起点和端点可以转化为n-1个连接桥的长度区间,把区间升序排列。

  对于m个桥升序排列,对于每一个桥枚举每个可以合法覆盖的区间,选取最优的,选取的时候满足L<bridge_length<R,L经是有序的了。我们只需选取R最小的那个,因为R越大,这个区间就能适应更多的桥。

  本宝宝对于选取最优区间的时候采用了优先队列,并不是最优的处理方式,大家有好的办法可以留言告诉弱弱。

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <cmath>
  7 #include <queue>
  8 using namespace std;
  9 
 10 const int maxn = 200010;
 11 #define LL __int64
 12 struct bridge
 13 {
 14     LL val, id;
 15     bool operator < (const bridge &a) const
 16     {
 17         return val < a.val;
 18     }
 19 } Bri[maxn];
 20 
 21 struct island
 22 {
 23     LL r, l, id;
 24     bool operator < (const island &a) const
 25     {
 26         return l < a.l;
 27     }
 28 } Is[maxn];
 29 struct node
 30 {
 31     LL s, id;
 32     bool operator < (const node &a) const
 33     {
 34         return s > a.s;
 35     }
 36 };
 37 
 38 LL vis[maxn], n, m;
 39 bool solve ()
 40 {
 41     priority_queue <node>Q;//当前桥可以搭建成功的区间
 42     int l=0;
 43     memset (vis, 0, sizeof(vis));
 44 
 45     for (int i=0; i<m; i++)//对于每个桥选取最优的区间搭建
 46     {
 47         node nu;
 48         while (!Q.empty())
 49         {
 50             nu = Q.top();
 51             if (nu.s < Bri[i].val)
 52                 Q.pop();//删除队列中的不合法区间
 53             else
 54                 break;
 55         }
 56 
 57         while (Bri[i].val>=Is[l].l && Is[l].r >= Bri[i].val && l<n-1)
 58         {
 59             nu.id = Is[l].id;
 60             nu.s = Is[l].r;
 61             Q.push (nu);//区间加进队列
 62             l ++;
 63         }
 64         if (Q.empty())
 65             continue;//没有合适的边,就继续循环加边
 66         nu = Q.top ();
 67         vis[nu.id] = Bri[i].id;//记录连接区间所对应的边
 68         Q.pop();
 69     }
 70     for (int i=1; i<n; i++)
 71         if (!vis[i])
 72             return false;
 73     return true;//所有区间都对应有边
 74 }
 75 int main ()
 76 {
 77     while (scanf ("%I64d %I64d", &n, &m) != EOF)
 78     {
 79         island pre, cur;
 80         LL i;
 81         scanf ("%I64d %I64d", &pre.l, &pre.r);
 82         for (i=1; i<n; i++)
 83         {
 84             scanf ("%I64d %I64d", &cur.l, &cur.r);
 85             Is[i-1].id = i;
 86             Is[i-1].l = cur.l - pre.r;
 87             Is[i-1].r = cur.r - pre.l;
 88             pre = cur;
 89         }
 90         for (i=0; i<m; i++)
 91         {
 92             Bri[i].id = i+1;
 93             scanf ("%I64d", &Bri[i].val);
 94         }
 95         sort (Is, Is+n-1);
 96         sort (Bri, Bri+m);
 97         if (solve ())
 98         {
 99             printf ("Yes\n");
100             for (i=1; i<n-1; i++)
101                 printf ("%I64d ", vis[i]);
102             printf ("%I64d\n", vis[i]);
103         }
104         else
105             printf ("No\n");
106     }
107     return 0;
108 }

 

转载于:https://www.cnblogs.com/alihenaixiao/p/4606248.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值