HDU 4415 Assassin's Creed(贪心)
2015-08-24 00:06
423 查看
HDU 4415
题意:
壮哉我Assassin!E叔有一柄耐久度为m的袖剑,以及n个目标士兵要去解决。
每解决掉一个士兵,消耗袖剑Ai的耐久度,且获得该士兵的武器,可以使用该武器解决Bi名其他士兵。
E叔要尽可能地消耗更少耐久度解决更多的敌人,求最小消耗与最大杀敌数。
思路:
我们把士兵分为两个集合:e1与e2,e1的士兵 Bi = 0 , e2 的 Bi > 0.我们发现,如果能解决e2的任意一个,e2即可全灭,那么我们对e2根据消耗进行升序排序,消灭e2集合的消耗即为排序后的第一个士兵的Ai;
其次,要尽可能多地解决e1的士兵,则同样对e1根据消耗进行升序排序,杀到耐久度小于下一士兵Ai为止;
乍一看,最优解就是先全灭e2再用剩下的耐久度消灭e1较小Ai的敌人,用e2剩下的Bi消耗e1较大Ai的敌人;
如果不能全灭e2,则用所有耐久度去解决e1的敌人。
这样做的确很优了,但还不是最优,考虑这组样例:
11
44 55
22 11
33 11
55 00
100100 00
按照刚才的贪心策略,先解决Bi > 0 的前两个士兵(用袖剑杀死士兵1,用士兵1的武器杀死士兵2),消耗2耐久度,然后用士兵2的武器解决Ai最大的士兵4,士兵3由于耐久度不够则无法解决,答案是3 2。
但是我们可以先用袖剑杀死士兵1与士兵2,用这两个士兵的武器去解决士兵3,4,明显最优解为4 5。
于是我们对之前贪心策略做出改进:
设用袖剑杀死一个 Bi = 0 的士兵1消耗为a,设用士兵武器杀死一个在 Bi > 0 的集合里的士兵2,士兵2的最小消耗为b;
如果a < b,则用袖剑解决士兵1,用士兵武器解决士兵2;
否则,则用袖剑解决士兵2,保留士兵武器解决更大消耗的士兵(可能是士兵1);
换而言之,就是E叔面对一个 Bi > 0 的士兵,他说:本来准备用士兵武器杀死你,现在我又不想了,我要用袖剑杀死你,因为你的消耗并不大,我要换回用以杀死你的士兵武器,去杀死消耗更大的敌人。
可能叙述还是有点不清。。这个贪心策略看起来极其像dp,然而它真心不是dp。。以后思路更清晰的时候再改改吧~
代码:
[code]/* * @author FreeWifi_novicer * language : C++/C */ #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #include<queue> using namespace std; #define clr( x , y ) memset(x,y,sizeof(x)) #define cls( x ) memset(x,0,sizeof(x)) #define mp make_pair #define pb push_back typedef long long lint; typedef long long ll; typedef long long LL; /*Nothing is true , everything is permitted*/ const int maxn = 1e5 + 100 ; lint n , m ; lint kill_e1 , cost1 ; lint ans_cost , ans_kill ; lint e1[maxn] ; struct em{ lint cos , kil ; }e2[maxn] ; bool cmp( em a , em b ){ return a.cos < b.cos ; } void only_kill_e1( int len1 ){ lint dur = m ; cost1 = 0 ; kill_e1 = 0 ; int k = 0 ; while( k < len1 && dur >= e1[k] ){ cost1 += e1[k] ; kill_e1 ++ ; dur -= e1[k++] ; } } bool kill_all_e2( int len2 , int len1 ){ if( !len2 ) return false ; lint dur = m ; if( e2[0].cos > dur ) return false ; dur -= e2[0].cos ; lint sumb = 0 ; for( int i = 0 ; i < len2 ; i++ ) sumb += e2[i].kil ; lint rest = sumb - len2 + 1 ; if( rest >= len1 ){//如果多余的sword能够解决掉所有b = 0的敌人,则可解决所有敌人 ans_cost = e2[0].cos ; ans_kill = n ; return true ; } else{ int i = 0 , j = 1 ; //比较e2[j].cos 与 e1[i]的大小,选择消耗耐久度小的去杀 lint tmp = len1 - rest ; ans_cost = e2[0].cos ; ans_kill = len2 + rest ; while( i < tmp ){ if( dur < e1[i] && dur < e2[j].cos ) break ; if( j < len2 && e2[j].cos <= e1[i] ){ ans_cost += e2[j].cos ; dur -= e2[j].cos ; tmp-- ; j++ ; } else{ ans_cost += e1[i] ; dur -= e1[i] ; i++ ; } ans_kill ++ ; } return true ; } } int main(){ // freopen("input.txt","r",stdin); int t ; cin >> t ; int kase = 1 ; while( t-- ){ cin >> n >> m ; ans_kill = kill_e1 = 0 ; ans_cost = cost1 = 0 ; lint len1 = 0 , len2 = 0 ; for( int i = 1 ; i <= n ; i++ ){ lint a , b ; scanf( "%I64d%I64d" , &a , &b ) ; if( !b ){ e1[len1++] = a ; } else{ e2[len2].cos = a ; e2[len2++].kil = b ; } } printf( "Case %d: " , kase++ ) ; sort( e1 , e1 + len1 ) ; sort( e2 , e2 + len2 , cmp ) ; only_kill_e1( len1 ) ; if( !kill_all_e2( len2 , len1 ) ){ printf( "%I64d %I64d\n" , kill_e1 , cost1 ) ; continue ; } if( ans_kill > kill_e1 ){ printf( "%I64d %I64d\n" , ans_kill , ans_cost ) ; } else{ if( ans_kill == kill_e1 ) printf( "%I64d %I64d\n" , ans_kill , min( ans_cost , cost1 ) ) ; else printf( "%I64d %I64d\n" , kill_e1 , cost1 ) ; } } return 0; }
相关文章推荐
- C++调用Lua编程环境搭建及测试代码示例
- Redis
- 例子需要包含头文件 #include <vector>
- 使用NSURLConnection实现大文件断点下载
- UVALive - 6268 Cycling 贪心
- So many many foods here!
- 正则表达式详解
- 栈和队列数据结构的基本概念及其相关的Python实现
- 正则表达式详解
- php析构函数的简单使用说明
- php实现递归的三种基本方式
- php 利用socket发送HTTP请求(GET,POST)
- PHP实现微信发红包程序
- Windows平台使用RMAN命令自动删除Oracle过期归档日志的方法
- 如何屏蔽防止别的网站嵌入框架代码
- js实现适用于素材网站的黑色多级菜单导航条效果
- jQuery实现的手机发送验证码倒计时效果代码分享
- Lua环境搭建之使用EditPlus搭建Lua开发环境
- 优化Markdown在Notepad++中的使用体验
- UVA - 1459 Flowers Placement(二分图+dfs)