mobile.365-838.comSwift 中枚举高级用法及实施

By admin in mobile.365-838.com on 2018年10月20日

title: “Swift 中枚举高级用法和执行”
date: 2015-11-20
tags: [APPVENTURE]
categories: [Swift 进阶]
permalink: advanced-practical-enum-examples

1.


[HNOI2001]
产品加工

本文链接=http://appventure.me/2015/10/17/advanced-practical-enum-examples/
作者=Benedikt Terhechte
初稿日期=2015-10-17
译者=pmst+小锅
校对=shanks
定稿=shanks

一致道简单的背包,然而我或写了大久QAQ
 

翻译注:作为一个走心且发生逼格的翻译组,我们对本篇文章中之代码都开展了认证,并且写了将代码分为前后两首做成了
playground,代码中产生详实的诠释。可以交斯github地址上进展下载,这个代码由翻译组的旁一样位小伙伴
ppt
提供。

岁月限制是都低于5
明白考虑同维背包,dp[i]意味着手上A消耗了i的最小B消耗

本文是同样首详细且具备实战意义之学科,涵盖几乎拥有枚举(Enum)知识点,为公解答Swift中枚举的行使场合和采取方法。

注意

和switch语句类似,Swift被之枚举乍看之下更像是C言语中枚举的进阶版,即允许你定义一栽档次,用于表示日常业务受到某种用例。不过深入挖掘后,凭借Swift骨子里特别的计划意见,相较C语言枚举来说那在骨子里状况被的利用越来越广大。特别是用作有力的工具,Swift未遭之枚举能够清楚表达代码的企图。

 if(b[i])
dp[j]=dp[j]+b[i];
 else dp[j]=1e9+7;

本文中,我们拿第一了解基础语法和运枚举的可能性,接着通过实战教你怎么与何时使用枚举。最后我们还会盖了解下Swift标准库中枚举是何等被应用的。

好用B则一直换,否则一经拿上亦然破的此状态设为正无根本,只能用后少只易。

业内开班修之前,先为出枚举的定义。之后我们以回过头再来谈谈其。

 

枚举声明的路是连可能状态的有限集,且可以有所附加值。通过内嵌(nesting),方法(method),关联值(associated
values
)和模式匹配(pattern
matching
),枚举可以划分层次地定义任何有集体的数额。

mobile.365-838.com 1mobile.365-838.com 2

深刻了解(Diving In)

简单概述如何定义跟运用枚举。

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn=6000+299;
const int N=5*6000+9;
int n,a[maxn],b[maxn],c[maxn],dp[N],lz[N],ans=1e9+7; 
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d%d",&a[i],&b[i],&c[i]);
    memset(dp,127,sizeof(dp));
    dp[0]=0;
    for(int i=1;i<=n;i++)
        for(int j=i*5;j>=0;j--){
            if(b[i]) dp[j]=dp[j]+b[i];
            else dp[j]=1e9+7;//!!!!!!!!!!!!!!!!!!!!
            if(a[i]&&j>=a[i]&&dp[j]>dp[j-a[i]]) dp[j]=dp[j-a[i]];
            if(c[i]&&j>=c[i]&&dp[j]>dp[j-c[i]]+c[i]) dp[j]=dp[j-c[i]]+c[i];
            if(i==n) ans=min(max(dp[j],j),ans);
        }
    cout<<ans;
    return 0;
}

概念基本的枚举类型(Defining Basic Enums)

试想我们在开发同悠悠打,玩家会为四个趋势动。所以喽,玩家的动轨迹中了限。显然,我们能够使枚举来抒发这同情景:

enum Movement{
    case Left
    case Right
    case Top
    case Bottom
}

继之,你得以又模式匹配结构获取到Movement的枚举值,或者按一定情景施行操作:

let aMovement = Movement.Left

// switch 分情况处理
switch aMovement{
case .Left: print("left")
default:()
}

// 明确的case情况
if case .Left = aMovement{
    print("left")
}

if aMovement == .Left { print("left") }

案例中,我们决不明确指出enum的其实名称(即case Move.Left:print("Left"))。因为路检查器能够自动为之进行路推算。这对于那些UIKit以及AppKit遭遇错综复杂的枚举是灰常有用的。

View
Code

枚举值(Enum Values)

自,你恐怕想只要呢enum中每个case分配一个价值。这一定有因此,比如枚举自身实际和某事或某物挂钩时,往往这些东西还要需要使用不同品类来表述。在C言语中,你只能为枚举case分红整型值,而Swift则提供了双重多的八面玲珑。

// 映射到整型
enum Movement: Int {
    case Left = 0
    case Right = 1
    case Top = 2
    case Bottom = 3
}

// 同样你可以与字符串一一对应
enum House: String {
    case Baratheon = "Ours is the Fury"
    case Greyjoy = "We Do Not Sow"
    case Martell = "Unbowed, Unbent, Unbroken"
    case Stark = "Winter is Coming"
    case Tully = "Family, Duty, Honor"
    case Tyrell = "Growing Strong"
}

// 或者float double都可以(同时注意枚举中的花式unicode)
enum Constants: Double {
    case π = 3.14159
    case e = 2.71828
    case φ = 1.61803398874
    case λ = 1.30357
}

对于StringInt花色来说,你还好忽略为枚举中的case赋值,Swift编译器也克正常干活。

// Mercury = 1, Venus = 2, ... Neptune = 8
enum Planet: Int {
    case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}

// North = "North", ... West = "West"
// 译者注: 这个是swift2.0新增语法
enum CompassPoint: String {
    case North, South, East, West
}

Swift枚举中支持以下四种植关联值类型:

  • 整型(Integer)
  • 浮点数(Float Point)
  • 字符串(String)
  • 布尔项目(Boolean)

因而若无法1呢枚举分配诸如CGPoint种类的价值。

设你想使读取枚举的值,可以由此rawValue性来促成:

let bestHouse = House.Stark
print(bestHouse.rawValue)
// prints "Winter is coming"

而是某种情形下,你或许想使经一个曾经部分raw value来创造一个enum case。这种情景下,枚举提供了一个点名构造方法:

enum Movement: Int {
    case Left = 0
    case Right = 1
    case Top = 2
    case Bottom = 3
}
// 创建一个movement.Right 用例,其raw value值为1
let rightMovement = Movement(rawValue: 1)

只要使用rawValue构造器,切记它是一个而难倒构造器(failable
initializer)。换言之,构造方法返回值为而选类型值,因为有时传入的值可能与自由一个case且未兼容。比如Movement(rawValue:42)

假定您想使因为底层 C
二前行制编码形式表现某物或某事,使得再具备可读性,这是一个要命实用之功效。例如,可以关押一下BSD
kqeue
library中的VNode
Flags
表明位之编码方式:

enum VNodeFlags : UInt32 {
    case Delete = 0x00000001
    case Write = 0x00000002
    case Extended = 0x00000004
    case Attrib = 0x00000008
    case Link = 0x00000010
    case Rename = 0x00000020
    case Revoke = 0x00000040
    case None = 0x00000080
}

然就可以假设你的DeleteWrite用例声明一目了然,稍后一旦得,只需要将raw
value
传 C 函数中即可。

 

嵌套枚举(Nesting Enums)

苟您有一定子类型的需要,可以针对enum开展嵌套。这样就是同意你吧实在的enum丁涵盖其他明显信息的enum。以RPG娱乐受之每个角色吧例,每个角色会享有武器,因此有着角色还得博与一个铁集合。而娱乐被的外实例则无从取这些家伙(比如食人魔,它们只使用棍棒)。

enum Character {
  enum Weapon {
    case Bow
    case Sword
    case Lance
    case Dagger
  }
  enum Helmet {
    case Wooden
    case Iron
    case Diamond
  }
  case Thief
  case Warrior
  case Knight
}

本,你可通过层级结构来叙述角色允许看的项目条。

let character = Character.Thief
let weapon = Character.Weapon.Bow
let helmet = Character.Helmet.Iron

2.

带有枚举(Containing Enums)

如出一辙地,你吗能够在structsclasses中内嵌枚举。接着上面的例证:

struct Character {
   enum CharacterType {
    case Thief
    case Warrior
    case Knight
  }
  enum Weapon {
    case Bow
    case Sword
    case Lance
    case Dagger
  }
  let type: CharacterType
  let weapon: Weapon
}

let warrior = Character(type: .Warrior, weapon: .Sword)

同样地,这吗将力促我们以相关的信汇总在一个职务。

[HAOI2007]上升序列

关联值(Associated Value)

关联值是将额外信息附加到enum case倍受之同种植最好之点子。打独比方,你在开同缓慢交易引擎,可能存在简单种不同之交易类型。除此之外每手交易还要制定明确的股票名称和贸易数据:

看数据范围似乎是n^2可以过的,然而自己之前并无会见写nlongn求最丰富齐升子序列的算法就和好YY了转,写得不得了可恶,单调栈里从少至长由深及多少,用了个别独次细分,一次于搜索找最丰富的较她有些的,一差找长度也她的职务是不是好创新。

简单易行例程(Simple Example)

enum Trade {
    case Buy
    case Sell
}
func trade(tradeType: Trade, stock: String, amount: Int) {}

而是股票的价值跟数码显然起属于市,让她们作单身的参数显得模棱两只是。你也许已经想到如果往struct遭遇内嵌一个枚举了,不过关联值提供了同一种植更舒适的化解方案:

enum Trade {
    case Buy(stock: String, amount: Int)
    case Sell(stock: String, amount: Int)
}
func trade(type: Trade) {}

这般找到为每个元素打头的极致丰富上升序列,询问就起1至n跑同全套询它能不能够到那么丰富,就确保了字典序最小。

模式匹配(Pattern Mathching)

假使你想要看这些价值,模式匹配重救场:

let trade = Trade.Buy(stock: "APPL", amount: 500)
if case let Trade.Buy(stock, amount) = trade {
    print("buy \(amount) of \(stock)")
}

mobile.365-838.com 3mobile.365-838.com 4

标签(Labels)

涉值未待增大标价签的宣示:

enum Trade {
   case Buy(String, Int)
   case Sell(String, Int)
}

万一你加加了,那么,每当创建枚举用例时,你都急需将这些标签标示出。

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<vector>
using namespace std;
const int maxn=10000+299;
int now,n,m,x,maxx,a[maxn],pre[maxn],dp[maxn],sta[maxn],sl=1,sr;
int ef(int l,int r,int x){
    int res=-1;
    while(l<=r){
        int mid=(l+r)>>1;
        if(a[sta[mid]]>x) res=mid,l=mid+1;
        else r=mid-1;
    }
    return res;
}
void ef2(int l,int r,int len,int x){
    while(l<=r){
        int mid=(l+r)>>1;
        if(dp[sta[mid]]==len) { if(a[sta[mid]]<=a[x]) sta[mid]=x; break;}
        if(dp[sta[mid]]<len) l=mid+1;
        else if(dp[sta[mid]]>len) r=mid-1;  
    }
}
void work() { 
    for(int i=n;i>=1;i--) {
        dp[i]=1;
        if(sl<=sr) {
        now=ef(sl,sr,a[i]);
        if(now!=-1)
            dp[i]=dp[sta[now]]+1;
        }
        maxx=max(maxx,dp[i]);
        while(sr>=sl&&dp[sta[sr]]<=dp[i]&&a[sta[sr]]<=a[i]) {
            sr--;
        }
        if(sr<sl||dp[sta[sr]]<dp[i]) sta[++sr]=i;
        else ef2(sl,sr,dp[i],i);
    }
}
void query(int x){
    if(x>maxx) puts("Impossible");
    else {
        int pre=0;
        for(int i=1;i<=n;i++) {
            if(dp[i]>=x&&a[i]>pre) {
                pre=a[i];
                if(x==1)
                printf("%d",a[i]);
                else printf("%d ",a[i]);
                x--;
                if(!x) break;
            }
        }
        printf("\n");
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    work();
    scanf("%d",&m);
    for(int i=1;i<=m;i++) {
        scanf("%d",&x);
        query(x); 
    }
    return 0;
}

(元组参数)Tuple as Arguments

重复重要之是,Swift其间有关消息实际是一个元组,所以若可像下这样做:

let tp = (stock: "TSLA", amount: 100)
let trade = Trade.Sell(tp)

if case let Trade.Sell(stock, amount) = trade {
    print("buy \(amount) of \(stock)")
}
// Prints: "buy 100 of TSLA"

语法允许而将元组当作一个简短的数据结构,稍后元组将机关转换到高档项目,就以enum case。想象一个应用程序可以叫用户来布局电脑:

typealias Config = (RAM: Int, CPU: String, GPU: String)

// Each of these takes a config and returns an updated config
func selectRAM(_ config: Config) -> Config {return (RAM: 32, CPU: config.CPU, GPU: config.GPU)}
func selectCPU(_ config: Config) -> Config {return (RAM: config.RAM, CPU: "3.2GHZ", GPU: config.GPU)}
func selectGPU(_ config: Config) -> Config {return (RAM: config.RAM, CPU: "3.2GHZ", GPU: "NVidia")}

enum Desktop {
   case Cube(Config)
   case Tower(Config)
   case Rack(Config)
}

let aTower = Desktop.Tower(selectGPU(selectCPU(selectRAM((0, "", "") as Config))))

布置的每个步骤都经过递元组到enum遇展开内容更新。倘若我们由函数式编程2饱受赢得启发,这将更换得再好。

infix operator <^> { associativity left }

func <^>(a: Config, f: (Config) -> Config) -> Config { 
    return f(a)
}

最终,我们得用不同安排步骤串联起来。这在布置步骤繁多的景下一定实用。

let config = (0, "", "") <^> selectRAM  <^> selectCPU <^> selectGPU
let aCube = Desktop.Cube(config)

View
Code

下案例(Use Case Example)

关联值可以以多智利用。常言道:一垛胜千言,
下面就是达几乎截简单的以身作则代码,这几段代码没有特定的各个。

// 拥有不同值的用例
enum UserAction {
  case OpenURL(url: NSURL)
  case SwitchProcess(processId: UInt32)
  case Restart(time: NSDate?, intoCommandLine: Bool)
}

// 假设你在实现一个功能强大的编辑器,这个编辑器允许多重选择,
// 正如 Sublime Text : https://www.youtube.com/watch?v=i2SVJa2EGIw
enum Selection {
  case None
  case Single(Range<Int>)
  case Multiple([Range<Int>])
}

// 或者映射不同的标识码
enum Barcode {
    case UPCA(numberSystem: Int, manufacturer: Int, product: Int, check: Int)
    case QRCode(productCode: String)
}

// 又或者假设你在封装一个 C 语言库,正如 Kqeue BSD/Darwin 通知系统:
// https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
enum KqueueEvent {
    case UserEvent(identifier: UInt, fflags: [UInt32], data: Int)
    case ReadFD(fd: UInt, data: Int)
    case WriteFD(fd: UInt, data: Int)
    case VnodeFD(fd: UInt, fflags: [UInt32], data: Int)
    case ErrorEvent(code: UInt, message: String)
}

// 最后, 一个 RPG 游戏中的所有可穿戴装备可以使用一个枚举来进行映射,
// 可以为一个装备增加重量和持久两个属性
// 现在可以仅用一行代码来增加一个"钻石"属性,如此一来我们便可以增加几件新的镶嵌钻石的可穿戴装备
enum Wearable {
    enum Weight: Int {
    case Light = 1
    case Mid = 4
    case Heavy = 10
    }
    enum Armor: Int {
    case Light = 2
    case Strong = 8
    case Heavy = 20
    }
    case Helmet(weight: Weight, armor: Armor)
    case Breastplate(weight: Weight, armor: Armor)
    case Shield(weight: Weight, armor: Armor)
}
let woodenHelmet = Wearable.Helmet(weight: .Light, armor: .Light)

 

术以及总体性(Methods and properties)

你吗可以在enum中像这样定义方法:

enum Wearable {
    enum Weight: Int {
        case Light = 1
    }
    enum Armor: Int {
        case Light = 2
    }
    case Helmet(weight: Weight, armor: Armor)
        func attributes() -> (weight: Int, armor: Int) {
       switch self {
             case .Helmet(let w, let a): return (weight: w.rawValue * 2, armor: w.rawValue * 4)
       }
    }
}
let woodenHelmetProps = Wearable.Helmet(weight: .Light, armor: .Light).attributes()
print (woodenHelmetProps)
// prints "(2, 4)"

枚举中之法门吗各个一个enum case使“生”。所以一旦想如果在一定情景实施一定代码的话,你待分支处理还是应用switch报句来家喻户晓正确的代码路径。

enum Device { 
    case iPad, iPhone, AppleTV, AppleWatch 
    func introduced() -> String {
       switch self {
         case AppleTV: return "\(self) was introduced 2006"
         case iPhone: return "\(self) was introduced 2007"
         case iPad: return "\(self) was introduced 2010"
         case AppleWatch: return "\(self) was introduced 2014"
       }
    }
}
print (Device.iPhone.introduced())
// prints: "iPhone was introduced 2007"

 

属性(Properties)

尽管增加一个仓储属性到枚举中莫为允许,但你还能够创立计算属性。当然,计算属性之情还是立以枚举值下要枚举关联值得到的。

enum Device {
  case iPad, iPhone
  var year: Int {
    switch self {
        case iPhone: return 2007
        case iPad: return 2010
     }
  }
}

只是对的nlogn求最丰富上升序列并无是如此形容的,只用一个二分,不过当生连无是颇懂得,懒得学以后再说吧。

静态方法(Static Methods)

若为会为枚举创建有静态方法(static methods)。换言之通过一个非枚举类型来创造一个枚举。在是示例中,我们得考虑用户有时用苹果设备叫错的状态(比如AppleWatch叫成iWatch),需要回到一个得体的称号。

enum Device { 
    case AppleWatch 
    static func fromSlang(term: String) -> Device? {
      if term == "iWatch" {
      return .AppleWatch
      }
      return nil
    }
}
print (Device.fromSlang("iWatch"))

于LLJ大佬那里学到了用线段树的做法,开平粒权值线段树,从晚向前把Dp值存进,每个点找她背后的最为要命Dp值来更新,感觉跟正规的nlogn的思路可能多。

可是易道(Mutating Methods)

方可声明也mutating。这样就算允许改变隐藏参数selfcase值了3

enum TriStateSwitch {
    case Off, Low, High
    mutating func next() {
    switch self {
    case Off:
        self = Low
    case Low:
        self = High
    case High:
        self = Off
    }
    }
}
var ovenLight = TriStateSwitch.Low
ovenLight.next()
// ovenLight 现在等于.On
ovenLight.next()
// ovenLight 现在等于.Off

 

小结(To Recap)

至此,我们已经大约了解了Swift中枚举语法的主导用例。在初步迈向进阶的路先头,让我们再审视文章开篇给有之概念,看看现在是否变得再清楚了。

枚举声明的类别是包括可能状态的有限集,且可享有附加值。通过内嵌(nesting),方法(method),关联值(associated
values
)和模式匹配(pattern
matching
),枚举可以划分层次地定义任何发生集体的数。

现行我们已针对性这概念更加鲜明了。确实,如果我们补充加关联值和嵌套,enum不畏看起就是比如一个封闭的、简化的struct。相比较struct,前者优势体现于会为分类及层次结构编码。

// Struct Example
struct Point { let x: Int, let y: Int }
struct Rect { let x: Int, let y: Int, let width: Int, let height: Int }

// Enum Example
enum GeometricEntity {
   case Point(x: Int, y: Int)
   case Rect(x: Int, y: Int, width: Int, height: Int)
}

计以及静态方法的长允许我们吧enum叠加功能,这象征无须依靠额外函数就会落实4

// C-Like example
enum Trade {
   case Buy
   case Sell
}
func order(trade: Trade)

// Swift Enum example
enum Trade {
   case Buy
   case Sell
   func order()
}

3.

枚举进阶(Advanced Enum Usage)

UVA – 12063 Zeros and
Ones

协议(Protocols)

自一度提及了structsenums期间的相似性。除了附加措施的力外,Swift否允许而以枚举中采用协议(Protocols)情商扩展(Protocol
Extension)

Swift商讨定义一个接口或项目为供应其他数据结构来照。enum自然也未例外。我们事先打Swift标准库中的一个例开始.

CustomStringConvertible举凡一个以打印为目的的自定义格式化输出的项目。

protocol CustomStringConvertible {
  var description: String { get }
}

欠协议就来一个渴求,即一个才念(getter)类型的字符串(String项目)。我们可以老轻吗enum兑现这协议。

enum Trade: CustomStringConvertible {
   case Buy, Sell
   var description: String {
       switch self {
       case Buy: return "We're buying something"
       case Sell: return "We're selling something"
       }
   }
}

let action = Trade.Buy
print("this action is \(action)")
// prints: this action is We're buying something

一些商量的贯彻可能用根据中状态来对号入座处理要求。例如定义一个管理银行账号的协商。

protocol AccountCompatible {
  var remainingFunds: Int { get }
  mutating func addFunds(amount: Int) throws
  mutating func removeFunds(amount: Int) throws
}

汝或许会略地拿struct贯彻之协议,但是考虑用之上下文,enum举凡一个还精明之处理办法。不过你无法上加一个囤属性到enum中,就像var remainingFuns:Int。那么你晤面如何组织为?答案灰常简单,你可行使关联值完美解决:

enum Account {
  case Empty
  case Funds(remaining: Int)

  enum Error: ErrorType {
    case Overdraft(amount: Int)
  }

  var remainingFunds: Int {
    switch self {
    case Empty: return 0
    case Funds(let remaining): return remaining
    }
  }
}

为维持代码清爽,我们得以以enum的情商扩展(protocl extension)中定义必须的商谈函数:

extension Account: AccountCompatible {

  mutating func addFunds(amount: Int) throws {
    var newAmount = amount
    if case let .Funds(remaining) = self {
      newAmount += remaining
    }
    if newAmount < 0 {
      throw Error.Overdraft(amount: -newAmount)
    } else if newAmount == 0 {
      self = .Empty
    } else {
      self = .Funds(remaining: newAmount)
    }
  }

  mutating func removeFunds(amount: Int) throws {
    try self.addFunds(amount * -1)
  }

}
var account = Account.Funds(remaining: 20)
print("add: ", try? account.addFunds(10))
print ("remove 1: ", try? account.removeFunds(15))
print ("remove 2: ", try? account.removeFunds(55))
// prints:
// : add:  Optional(())
// : remove 1:  Optional(())
// : remove 2:  nil

无独有偶而您所见的,我们由此以价值存储到enum cases遇落实了商事抱有要求项。如此做法还有一个好玩的地方:现在举代码基础及而只是待一个模式匹配就会测试空账号输入的景况。你免待关注剩余资金是否等零。

而且,我们呢于账号(Accout)面临内嵌了一个随ErrorType合计的枚举,这样咱们虽得采取Swift2.0语法来展开错误处理了。这里叫出又详尽的利用案例教程。

 

style=”font-family: "Microsoft YaHei"; font-size: 15px”>二前行制数和她的各类模式对于电脑程序员来说总是特别幽默之。
在这个
style=”font-family: "Microsoft YaHei"; font-size: 15px”>您要计算有所以下属性之正数二迈入制数的题材:
style=”font-family: "Microsoft YaHei"; font-size: 15px”>•数字正好是N位宽,它们并未带零。
style=”font-family: "Microsoft YaHei"; font-size: 15px”>•一和零的效率相当。
style=”font-family: "Microsoft YaHei"; font-size: 15px”>•数字是K的倍数。
style=”font-family: "Microsoft YaHei"; font-size: 15px”>输入
style=”font-family: "Microsoft YaHei"; font-size: 15px”>输入文件包含几单测试用例。
输入的首先行而提供了测试用例数,
style=”font-family: "Microsoft YaHei"; font-size: 15px”>T(1≤T≤100)。
那么T测试用例会随,每一行还当一行。 每个测试用例的输入包括
style=”font-family: "Microsoft YaHei"; font-size: 15px”>的一定量独整数,N(1≤N≤64)和K(0≤K≤100)。
style=”font-family: "Microsoft YaHei"; font-size: 15px”>产量
style=”font-family: "Microsoft YaHei"; font-size: 15px”>对于每组输入,首先打印测试用例编号。
然后打印二前进制数的数字 style=”font-family: "Microsoft YaHei"”>

 

扩展(Extensions)

正而刚所显现,枚举也得拓展扩张。最明确的用例就是以枚举的casemethod暌违,这样看你的代码能够简单高效地消化掉enum情节,紧接着转移到方法定义:

enum Entities {
    case Soldier(x: Int, y: Int)
    case Tank(x: Int, y: Int)
    case Player(x: Int, y: Int)
}

现在,我们为enum扩展方法:

extension Entities {
   mutating func move(dist: CGVector) {}
   mutating func attack() {}
}

若平好由此描写一个扩大来以一个一定的合计:

extension Entities: CustomStringConvertible {
  var description: String {
    switch self {
       case let .Soldier(x, y): return "\(x), \(y)"
       case let .Tank(x, y): return "\(x), \(y)"
       case let .Player(x, y): return "\(x), \(y)"
    }
  }
}

 

枚举泛型(Generic Enums)

枚举也支持泛型参数定义。你可利用其盖适应枚举中之涉值。就以直接来源Swift标准库中之粗略例子来说,即Optional色。你要可能由此以下几种方法使用它:可选链(optional chaining(?))、if-let可选绑定、guard let、或switch,但是打语法角度来说你为堪如此使用Optional:

let aValue = Optional<Int>.Some(5)
let noValue = Optional<Int>.None
if noValue == Optional.None { print("No value") }

这是Optional极致直白的用例,并未使用外语法糖,但是不可否认Swift中语法糖的加盟使得你的办事双重简便。如果您相地方的实例代码,你或就猜到Optional里头贯彻是这么的5:

// Simplified implementation of Swift's Optional
enum MyOptional<T> {
  case Some(T)
  case None
}

这里发生吗特别为?注意枚举的关联值采用泛型参数T作为自己类型,这样可选类型构造任何你想使的回值。

枚举可以拥有多单泛型参数。就以熟知的Either类为条例,它不用是Swift标准库中之一律有,而是实现让多开源库以及
任何函数式编程语言,比如HaskellF#。设计想法是这样的:相较单纯返回一个价值或尚未价值(née
Optional),你再次要返回一个成功值或者有申报信息(比如错误值)。

// The well-known either type is, of course, an enum that allows you to return either
// value one (say, a successful value) or value two (say an error) from a function
enum Either<T1, T2> {
  case Left(T1)
  case Right(T2)
}

最后,Swift遭受颇具在classstruct受到奏效的类别约束,在enum遭遇平等适用。

// Totally nonsensical example. A bag that is either full (has an array with contents)
// or empty.
enum Bag<T: SequenceType where T.Generator.Element==Equatable> {
  case Empty
  case Full(contents: T)
}

谷歌翻译神坑,1跟0频率相同翻译成0和0频率相同,喵喵喵?

递归 / 间接(Indirect)类型

间接类型是 Swift 2.0 新增的一个种。 它们允许以枚举中一个 case
的关联值再次定义为枚举。举个例子,假而我们怀念定义一个文件系统,用来代表文件及含有文件之目。如果以文件目录概念也枚举的
case,则目录 case
的关联值应该重包含一个文件的数组作为其的关系值。因为这是一个递归的操作,编译器需要针对这个开展一个不同寻常之预备。Swift
文档中是这么写的:

枚举和 case
可以吃标记为间接的(indrect),这意味它们的关联值是吃间接保存的,这允许我们定义递归的数据结构。

为此,如果我们如果定义 FileNode 的枚举,它应有会是如此的:

enum FileNode {
  case File(name: String)
  indirect case Folder(name: String, files: [FileNode])
}

此处的 indrect 关键字告诉编译器间接地拍卖此枚举的
case。也可本着全枚举类型应用此要字。用作例子,我们来定义一个二叉树:

indirect enum Tree<Element: Comparable> {
    case Empty
    case Node(Tree<Element>,Element,Tree<Element>)
}

眼看是一个雅强大的风味,可以吃咱之所以生简单之方式来定义一个兼有复杂关系的数据结构。

将Case打成case被坑了一波。。对碰才发现QAQ

以于定义类型作为枚举的价

如我们忽视关联值,则枚举的价值就只能是整型,浮点型,字符串和布尔档次。如果想如果支持别的路,则足以由此实现
StringLiteralConvertible
协议来成功,这足以为咱们通过对字符串的序列化和反序列化来若枚举支持自定义类型。

用作一个例证,假而我们设定义一个枚举来保存不同的 iOS 设备的屏幕尺寸:

enum Devices: CGSize {
   case iPhone3GS = CGSize(width: 320, height: 480)
   case iPhone5 = CGSize(width: 320, height: 568)
   case iPhone6 = CGSize(width: 375, height: 667)
   case iPhone6Plus = CGSize(width: 414, height: 736)
}

可是,这段代码不可知通过编译。因为 CGPoint
并无是一个常量,不克为此来定义枚举的价。我们得也怀念只要支持之自定义类型增加一个恢宏,让那个实现
StringLiteralConvertible
协议。这个协议要求我们贯彻三独构造方法,这三个艺术还需使用一个String花色的参数,并且我们用拿这个字符串转换成我们得之种(此处是CGSize)。

extension CGSize: StringLiteralConvertible {
    public init(stringLiteral value: String) {
    let size = CGSizeFromString(value)
    self.init(width: size.width, height: size.height)
    }

    public init(extendedGraphemeClusterLiteral value: String) {
    let size = CGSizeFromString(value)
    self.init(width: size.width, height: size.height)
    }

    public init(unicodeScalarLiteral value: String) {
    let size = CGSizeFromString(value)
    self.init(width: size.width, height: size.height)
    }
}

今便可来实现我们得之枚举了,不过这里发生一个缺点:初始化的价必须写成字符串形式,因为就即是咱们定义的枚举需要接受之类型(记住,我们实现了
StringLiteralConvertible,因此String得转正成CGSize类型)

enum Devices: CGSize {
   case iPhone3GS = "{320, 480}"
   case iPhone5 = "{320, 568}"
   case iPhone6 = "{375, 667}"
   case iPhone6Plus = "{414, 736}"
}

算是,我们好用 CGPoint 类型的枚举了。需要注意的凡,当要博得真实的
CGPoint 的价值的时,我们用拜访枚举的凡 rawValue 属性。

let a = Devices.iPhone5
let b = a.rawValue
print("the phone size string is \(a), width is \(b.width), height is \(b.height)")
// prints : the phone size string is iPhone5, width is 320.0, height is 568.0

下字符串序列化的款型,会于动用自定义类型的枚举比较困难,然而在某些特定的场面下,这吗会见被咱多多方便(比较使用NSColor
/
UIColor的当儿)。不仅如此,我们了好对协调定义之项目应用这个办法。

极致好之做法是通向后加0或者1
不用特判,不会见炸整,往前加之言语虽设特判,然后小心开 long long
,要模两不良保证非见面炸 (LLJ大佬说如果开始usinged long long ,因为 long long
只至2^64-1,实际及时书只交2^63就此并非)

本着枚举的关联值进行较

每当日常情况下,枚举是特别轻开展相等性判断的。一个简单易行的
enum T { case a, b } 实现默认支持相等性判断 T.a == T.b, T.b != T.a

不过,一旦我们呢枚举增加了涉及值,Swift
就没艺术是地啊简单只枚举进行相等性判断,需要我们好实现 ==
运行符。这并无是颇拮据:

enum Trade {
    case Buy(stock: String, amount: Int)
    case Sell(stock: String, amount: Int)
}
func ==(lhs: Trade, rhs: Trade) -> Bool {
   switch (lhs, rhs) {
     case let (.Buy(stock1, amount1), .Buy(stock2, amount2))
       where stock1 == stock2 && amount1 == amount2:
       return true
     case let (.Sell(stock1, amount1), .Sell(stock2, amount2))
       where stock1 == stock2 && amount1 == amount2:
       return true
     default: return false
   }
}

恰使我辈所展现,我们通过 switch 语句针对有限只枚举的 case
进行判定,并且只有当其的 case 是相当的上(比如 Buy 和
Buy)才对它的实际关联值进行判定。

mobile.365-838.com 5mobile.365-838.com 6

从今定义构造方法

静态方法
一节中间我们早已干她可作为从不同数额构造枚举的便民形式。在前的例子里为展示了,对出版社经常误用的苹果设备名返回正确的名字:

enum Device { 
    case AppleWatch 
    static func fromSlang(term: String) -> Device? {
      if term == "iWatch" {
      return .AppleWatch
      }
      return nil
    }
}

俺们为足以采用于定义构造方法来替换静态方法。枚举与结构体和相近的构造方法最充分之不比在,枚举的构造方法需要用隐式的
self 属性设置也科学的 case。

enum Device { 
    case AppleWatch 
    init?(term: String) {
      if term == "iWatch" {
      self = .AppleWatch
      }
      return nil
    }
}

在这个事例中,我们采取了而是难倒(failable)的构造方法。但是,普通的构造方法也得以干活得好好:

enum NumberCategory {
   case Small
   case Medium
   case Big
   case Huge
   init(number n: Int) {
    if n < 10000 { self = .Small }
    else if n < 1000000 { self = .Medium }
    else if n < 100000000 { self = .Big }
    else { self = .Huge }
   }
}
let aNumber = NumberCategory(number: 100)
print(aNumber)
// prints: "Small"
//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
typedef unsigned long long LL;
const int maxn=100;
const int maxk=105;
int T,n,k;
LL dp[maxn][maxn][maxk],ans,ll=1; 
void work(){
    if(!k||n&1) {printf("0\n"); return;}
    memset(dp,0,sizeof(dp));
    dp[0][0][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=i;j++) 
            for(int l=0;l<k;l++) {
               if(j) dp[i][j][(l+((ll=1)<<(i-1))%k)%k]+=dp[i-1][j-1][l];
               if(i!=n) dp[i][j][l]+=dp[i-1][j][l];
            }
    ans=0;
    printf("%llu\n",dp[n][n/2][0]);
}
int main()
{

    scanf("%d",&T);
    for(int i=1;i<=T;i++){
        scanf("%d%d",&n,&k);
        printf("Case %d: ",i);
        work(); 
    }
    return 0;
}

本着枚举的 case 进行迭代

一个特别经常于提问到之问题即使是什么对枚举中之 case
进行迭代。可惜的是,枚举并没有遵守SequenceType商事,因此尚未一个官的做法来对该展开迭代。取决于枚举的种类,对那个进展迭代可能吧简要,也闹或大艰苦。在StackOverflow高达出一个不胜好之座谈贴。贴子里面讨论到之不同景象太多了,如果只有在此间摘取一些会见发出片面性,而设拿满气象都排下,则会尽多。

View
Code

对 Objective-C 的支持

依据整型的枚举,如 enum Bit: Int { case Zero = 0; case One = 1 }
可以由此 @objc 标识来将那个桥接到 Objective-C
当中。然而,一旦用整型之外的类型(如
String)或者开始下关联值,我们虽无法在 Objective-C
当中以这些枚举了。

来一个号称也_ObjectiveCBridgeable的隐蔽协议,可以吃规范我们为定义合适的艺术,如此一来,Swift
便足以正确地以枚举转成为 Objective-C
类型,但自猜者协议于藏起来自然是来原因的。然而,从理论及来讲,这个协议要允许我们以枚举(包括实际枚举值)正确地桥接到
Objective-C 当中。

然,我们并不一定非要是使用方面提到的此法。为枚举添加两个方式,使用
@objc
定义一个替代类型,如此一来我们便足以任意地将枚举进行转移了,并且这种艺术不需要遵守私有协议:

enum Trade {
    case Buy(stock: String, amount: Int)
    case Sell(stock: String, amount: Int)
}

// 这个类型也可以定义在 Objective-C 的代码中
@objc class OTrade: NSObject {
    var type: Int
    var stock: String
    var amount: Int
    init(type: Int, stock: String, amount: Int) {
    self.type = type
    self.stock = stock
    self.amount = amount
    }
}

extension Trade  {

    func toObjc() -> OTrade {
    switch self {
    case let .Buy(stock, amount):
        return OTrade(type: 0, stock: stock, amount: amount)
    case let .Sell(stock, amount):
        return OTrade(type: 1, stock: stock, amount: amount)
    }
    }

    static func fromObjc(source: OTrade) -> Trade? {
    switch (source.type) {
    case 0: return Trade.Buy(stock: source.stock, amount: source.amount)
    case 1: return Trade.Sell(stock: source.stock, amount: source.amount)
    default: return nil
    }
    }
}

斯点子有一个之短,我们用将枚举映射为 Objective-C 中之 NSObject
基础项目(我们也得以一直以
NSDictionary),但是,当我们相遇有着实需要每当 Objective-C
当中得到有关联值的枚举时,这是一个可使的不二法门。

 

枚举底层

Erica Sadun
写过相同首十分流弊的至于枚举底层的博客,涉及到枚举底层的一体。在生代码中不用应该运用及这些东西,但是学习一下要么相当幽默的。在此地,我准备就关乎那篇博客中同长条,如果想打听再多,请走至原文:

枚举通常都是一个字节长度。[…]假使你确实非常愚蠢很天真,你本来好定义一个起那么些独
case
的枚举,在这种景象下,取决于最少所用之比特数,枚举可能占两独字节或者又多。

顿时是望后加的本

Swift 标准库中之枚举

当咱们准备继续探索枚举在品种中之不同用例之前,先看一下当 Swift
标准库当中是怎样行使枚举可能会见更诱人,所以现在于我们先来探。

Bit
这个枚举有三三两两独价值,OneZero。它深受看做 CollectionOfOne<T>
中的 Index 类型。

FloatingPointClassification
这个枚举定义了千篇一律多样 IEEE 754 可能的色,比如 NegativeInfinity,
PositiveZeroSignalingNaN

Mirror.AncestorRepresentation

Mirror.DisplayStyle
这有限独枚举被用当 Swift 反射 API 的上下文当中。

Optional
这个就算不用多说了

Process
这个枚举包含了时经过的吩咐执行参数(Process.argc,
Process.arguments)。这是一个相当幽默之枚举类型,因为在 Swift 1.0
当中,它是于用作一个组织体来实现之。

    for(int i=1;i<n;i++)
        for(int j=0;j<=i;j++) 
            for(int l=0;l<k;l++) {
               dp[i+1][j+1][((l<<1)|1)%k]+=dp[i][j][l];
               dp[i+1][j][(l<<1)%k]+=dp[i][j][l];
            }

行用例

咱曾经当前边几个小节当中看了了过多使得之枚举类型。包括
OptionalEither, FileNode
还发出二叉树。然而,还留存很多场地,使用枚举要大了用结构体和相近。一般来讲,如果问题得以为分解为寡的差品种,则采取枚举应该就是是正确的挑选。即使只有来个别种
case,这也是一个使用枚举的到场景,正而 Optional 和 Either
类型所出示的。

以下列举了有的枚举类型在实战中之采用示例,可以用来放你的创造力。

 

错误处理

说到枚举的实施以,当然必不可少在 Swift 2.0
当中新推出的错误处理。标记为而丢来的函数可以抛出任何遵守了 ErrorType
空协议的路。正使 Swift 官方文档中所描写的:

Swift
的枚举特别适用于构建平组有关的失实状态,可以透过关联值来为夫增加额外的增大信。

作一个示范,我们来拘禁下风行的JSON解析框架
Argo。当
JSON 解析失败的时段,它发生或是以下简单种主要缘由:

  1. JSON 数据不够某些最终模型所要之键(比如您的模子产生一个 username
    的属性,但是 JSON 中少了)
  2. 存项目不匹配,比如说 username 需要的凡 String 类型,而 JSON
    中涵盖的是
    NSNull6

除外,Argo 还吧非含在上述两独品种吃的左提供了于定义错误。它们的
ErrorType 枚举是相近这样的:

enum DecodeError: ErrorType {
  case TypeMismatch(expected: String, actual: String)
  case MissingKey(String)
  case Custom(String)
}

备的 case 都发出一个关系值用来含有关于误的附加信。

一个更为通用的用来完整 HTTP / REST API
错误处理的ErrorType应该是近似这样的:

enum APIError : ErrorType {
    // Can't connect to the server (maybe offline?)
    case ConnectionError(error: NSError)
    // The server responded with a non 200 status code
    case ServerError(statusCode: Int, error: NSError)
    // We got no data (0 bytes) back from the server
    case NoDataError
    // The server response can't be converted from JSON to a Dictionary
    case JSONSerializationError(error: ErrorType)
    // The Argo decoding Failed
    case JSONMappingError(converstionError: DecodeError)
}

这个 ErrorType 实现了整体的 REST
程序栈解析有或出现的失实,包含了富有在条分缕析结构体与类时会起的荒唐。

假使你看得足够细致,会发现于JSONMappingError中,我们将Argo中的DecodeError包裹到了咱们的APIError项目中,因为咱们会因此
Argo 来作实际的 JSON 解析。

复多关于ErrorType及这种植枚举类型的言传身教可以参照官方文档。

4.

观察者模式

每当 Swift 当中,有许多措施来构建观察模式。如果运用 @objc
兼容标记,则我们得采取 NSNotificationCenter 或者
KVO。即使不用此符号,didSet语法也堪充分易地贯彻简单的考察模式。在这里可以动用枚举,它好要受观察者的变更更清晰明了。设想我们要对一个成团进行观测。如果我们稍事思考一下便会见发现就无非发几栽可能的气象:一个或者多单宗为插入,一个或多只桩为去除,一个还是多独宗于更新。这任起就是是枚举可以做到的劳作:

enum Change {
     case Insertion(items: [Item])
     case Deletion(items: [Item])
     case Update(items: [Item])
}

尔后,观察对象就是足以用一个挺简单之方来抱已经出的事情的详细信息。这为堪通过为那个多
oldValuenewValue 的略方法来扩大其的效果。

UVA – 1628 Pizza
Delivery

状态码

使我们正在以一个表面系统,而者系统运用了状态码(或者错误码)来传递错误信息,类似
HTTP
状态码,这种气象下枚举就是一致种植异常醒目并且非常好之主意来针对信息进行包装7

enum HttpError: String {
  case Code400 = "Bad Request"
  case Code401 = "Unauthorized"
  case Code402 = "Payment Required"
  case Code403 = "Forbidden"
  case Code404 = "Not Found"
}

自家容易记忆化搜索,记忆化搜索最强。

结果类型映射(Map Result Types)

枚举也时不时被用来将 JSON 解析后底结果映射成 Swift
的原生类型。这里发出一个简易的事例:

enum JSON {
    case JSONString(Swift.String)
    case JSONNumber(Double)
    case JSONObject([String : JSONValue])
    case JSONArray([JSONValue])
    case JSONBool(Bool)
    case JSONNull
}

类似地,如果我们解析了其余的事物,也可以动用这种方法以分析结果转化我们
Swift 的项目。

dp[i][j][o][k]意味着i到j的订单已处理好,现在在i或者j
还要送k家的最为优解

UIKit 标识

枚举可以用来以字符串类型的录取标识或 storyboard
标识映射为项目系统可以展开反省的档次。假设我们发一个兼有不少原型 Cell 的
UITableView:

enum CellType: String {
    case ButtonValueCell = "ButtonValueCell"
    case UnitEditCell = "UnitEditCell"
    case LabelCell = "LabelCell"
    case ResultLabelCell = "ResultLabelCell"
}

枚举,记忆化

单位

单位和单位转换是任何一个采取枚举的绝佳场所。可以以单位会同相应的转换率映射起来,然后上加计来对单位开展机动的转移。以下是一个一定简单的演示:

enum Liquid: Float {
  case ml = 1.0
  case l = 1000.0
  func convert(amount amount: Float, to: Liquid) -> Float {
      if self.rawValue < to.rawValue {
     return (self.rawValue / to.rawValue) * amount
      } else {
     return (self.rawValue * to.rawValue) * amount
      }
  }
}
// Convert liters to milliliters
print (Liquid.l.convert(amount: 5, to: Liquid.ml))

别一个演示是圆的转换。以及数学符号(比如角度以及弧度)也得从中受益。

for(int i=1;i<l;i++) u=max(u,dfs(i,r,0,k-1)+e[i]-k*abs(p[i]-p[o==0?l:r]));
    for(int i=n;i>r;i--) u=max(u,dfs(l,i,1,k-1)+e[i]-k*abs(p[i]-p[o==0?l:r]));

游戏

戏吧是枚举中的外一个一定好之用例,屏幕及的绝大多数实体都属于一个一定种族的项目(敌人,障碍,纹理,…)。相对于本地的
iOS 或者 Mac
应用,游戏又像是一个白板。即开娱乐我们好采用全新的对象及新的干创造一个新的社会风气,而
iOS 或者 OSX 需要用预定义的 UIButtons,UITableViews,UITableViewCells
或者 NSStackView.

不仅如此,由于枚举可以遵守协议,我们可使协议扩展及根据协议的编程为不同吧打定义之枚举增加效益。这里是一个于是来显示这种层级的之简约示例:

enum FlyingBeast { case Dragon, Hippogriff, Gargoyle }
enum Horde { case Ork, Troll }
enum Player { case Mage, Warrior, Barbarian }
enum NPC { case Vendor, Blacksmith }
enum Element { case Tree, Fence, Stone }

protocol Hurtable {}
protocol Killable {}
protocol Flying {}
protocol Attacking {}
protocol Obstacle {}

extension FlyingBeast: Hurtable, Killable, Flying, Attacking {}
extension Horde: Hurtable, Killable, Attacking {}
extension Player: Hurtable, Obstacle {}
extension NPC: Hurtable {}
extension Element: Obstacle {}

在意及时等同段子先搜两限又中,可以达成记忆化效果

字符串类型化

于一个小好一点之 Xcode
项目面临,我们很快便会出雷同万分堆通过字符串来访问的资源。在前面的小节中,我们曾领过用标识及
storyboard
的标识,但是除此之外及时有限种,还留存诸多资源:图像,Segues,Nibs,字体和任何资源。通常状态下,这些资源还可以分成不同的集结。如果是这样的话,一个类型化的字符串会是一个让编译器帮我们进行路检查的好点子。

enum DetailViewImages: String {
  case Background = "bg1.png"
  case Sidebar = "sbg.png"
  case ActionButton1 = "btn1_1.png"
  case ActionButton2 = "btn2_1.png"
}

对于 iOS
开发者,R.swift夫第三方库可以吗上述关联的状态自动生成结构体。但是多少上你或要来双重多的控制(或者你恐怕是一个Mac开发者8)。

代码

API 端点

Rest API 是枚举的绝佳用例。它们还是分组的,它们还是零星的 API
集合,并且它也或会见来增大的询问或者命名的参数,而就足以下关联值来兑现。

此出个 Instagram
API
的简化版:

enum Instagram {
  enum Media {
    case Popular
    case Shortcode(id: String)
    case Search(lat: Float, min_timestamp: Int, lng: Float, max_timestamp: Int, distance: Int)
  }
  enum Users {
    case User(id: String)
    case Feed
    case Recent(id: String)
  }
}

Ash
Furrow的Moya框架虽是主导是考虑,使用枚举对
rest 端点进行映射。

mobile.365-838.com 7mobile.365-838.com 8

链表

Airspeed
Velocity有一篇极好的稿子说明了何等以枚举来落实一个链表。那篇文章被的大部代码都过了枚举的知识,并提到到了汪洋其他有趣的主题9,但是,链表最核心的定义是近乎这样的(我本着那个进行了有简化):

enum List {
    case End
    indirect case Node(Int, next: List)
}

各国一个节点(Node) case 都凭借于了下一个 case,
通过行使枚举而休其他种类,我们可以免采用一个可选的 next
类型以用来表示链表的竣工。

Airspeed Velocity 还写了同样篇超赞的博客,关于什么用 Swift
的间接枚举类型来兑现开门红黑树,所以如果你就读过有关链表的博客,你可能想延续看就首关于红黑树的博客。

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn=100+5;
int T,now,dp[maxn][maxn][2][maxn],vis[maxn][maxn][2][maxn],n,p[maxn],e[maxn],ans;
int dfs(int l,int r,int o,int k) {
    if(k==0) return 0;
    if(vis[l][r][o][k]==now) return dp[l][r][o][k];
    vis[l][r][o][k]=now;
    int &u=dp[l][r][o][k];
    u=0;
    for(int i=1;i<l;i++) u=max(u,dfs(i,r,0,k-1)+e[i]-k*abs(p[i]-p[o==0?l:r]));
    for(int i=n;i>r;i--) u=max(u,dfs(l,i,1,k-1)+e[i]-k*abs(p[i]-p[o==0?l:r]));
    return u;  
}
int main()
{
    scanf("%d",&T);
    for(now=1;now<=T;now++) {
    ans=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&p[i]);
    for(int i=1;i<=n;i++) scanf("%d",&e[i]);
    for(int kk=1;kk<=n;kk++) 
        for(int i=1;i<=n;i++)
        ans=max(ans,dfs(i,i,0,kk-1)+e[i]-kk*abs(p[i]));
    printf("%d\n",ans); 
    }
    return 0;
}

装字典(Setting Dictionaries)

这是 Erica Sadun
提出的颇深快的化解方案。简单来讲,就是其他我们需要因此一个特性之字典来对一个桩进行安装的时刻,都应有用同一系列有关联值的枚举来代替。使用即时办法,类型检查体系可保证布局的值都是不利的色。

关于更多的细节,以及方便的例证,可以翻阅下它们底篇章。

View
Code

局限

以及之前好像,我将见面因此同样名目繁多枚举的局限性来终结本篇文章。

 

领关联值

David
Owens写过一样首文章,他觉得眼前底关联值提取方式是可怜笨重的。我墙裂推荐您去看一下他的原文,在此自己对其的比方旨进行下说明:为了打一个枚举中取得涉及值,我们不能不用模式匹配。然而,关联值就是关联在一定枚举
case 的神速元组。而元组是足以采取重复简便易行的办法来取她其中价,即
.keyword 或者 .0

// Enums
enum Ex { case Mode(ab: Int, cd: Int) }
if case Ex.Mode(let ab, let cd) = Ex.Mode(ab: 4, cd: 5) {
    print(ab)
}
// vs tuples:
let tp = (ab: 4, cd: 5)
print(tp.ab)

苟你吧一如既往觉得我们相应下相同之章程来对枚举进行解构(deconstruct),这里来只
rdar:
rdar://22704262
(译者注:一上马自非知情 rdar 是啥意思,后来本人 google
了产,如果你吧生趣味,也得好去摸一下)

5.BZOJ 1009
[HNOI2008]GT考试

相等性

抱有关联值的枚举没有遵守 equatable
协议。这是一个遗憾,因为其吧广大业务多了未必要之错综复杂与辛苦。深层的原故恐怕是盖关联值的底色以是使了元组,而元组并没有遵守
equatable 协议。然而,对于限的 case
子集,如果这些关联值的色且守了 equatable
类型,我道编译器应该默认为那个生成 equatable 扩展。

// Int 和 String 是可判等的, 所以 Mode 应该也是可判等的
enum Ex { case Mode(ab: Int, cd: String) }

// Swift 应该能够自动生成这个函数
func == (lhs: Ex.Mode, rhs: Ex.Mode) -> Bool {
    switch (lhs, rhs) {
       case (.Mode(let a, let b), .Mode(let c, let d)):
       return a == c && b == d
       default:
       return false
    }
}

同一开始傻逼地kmp直接为前面跨一个即便停了,后来改成了并且调了许久发现自己Kmp写错了,贼难让。。

元组(Tuples)

绝可怜之问题即是指向元组的支持。我欣赏使用元组,它们可以假设多事务变得又简明,但是他们即还地处无文档状态又以成千上万场所都无法用。在枚举当中,我们无能为力以元组作为枚举的价:

enum Devices: (intro: Int, name: String) {
  case iPhone = (intro: 2007, name: "iPhone")
  case AppleTV = (intro: 2006, name: "Apple TV")
  case AppleWatch = (intro: 2014, name: "Apple Watch")
}

即时犹如看起连无是一个最为好之以身作则,但是咱只要开采取枚举,就见面时陷入到得用到接近上面这示例的景被。

尽管kmp转移然后矩阵优化。

迭代枚举的富有case

本条我们已经在前方议论过了。目前尚并未一个雅好的法来抱枚举中之有着
case 的汇聚以使我们可以对那个进行迭代。

mobile.365-838.com 9mobile.365-838.com 10

默认关联值

另一个会面遇到的事是枚举的关联值总是类型,但是我们倒是束手无策也这些类别指定默认值。假设有这样同样种情形:

enum Characters {
  case Mage(health: Int = 70, magic: Int = 100, strength: Int = 30)
  case Warrior(health: Int = 100, magic: Int = 0, strength: Int = 100)
  case Neophyte(health: Int = 50, magic: Int = 20, strength: Int = 80)
}

咱们照样可采取不同的价值创造新的 case,但是角色的默认设置依然会叫射。

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
int ans,n,m,p,top,a[21],nxt[21],cnt[21],vis[11];
struct jz{
    int x[21][21];
    friend jz operator *(const jz&l,const jz&r){
         jz res;
         for(int i=0;i<21;i++)
         for(int j=0;j<21;j++)
         res.x[i][j]=0;
         for(int i=0;i<21;i++)
             for(int j=0;j<21;j++) {
                 for(int k=0;k<21;k++)
                     (res.x[i][j]+=(l.x[i][k]*r.x[k][j])%p)%=p;
             } 
         return res;
    }
}base,ret,tmp;
void input() {
    scanf("%d%d%d",&n,&m,&p);
    char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) a[++top]=ch-'0';
}
int make_nxt(int a[],int *nxt) {
    for (int j=0,i=2;i<=m;i++) {
        while (j&&a[j+1]!=a[i]) j=nxt[j];
        if (a[j+1]==a[i]) j++;
        nxt[i]=j;
     }
}
void ksm(int b){
    while(b){
        if(b&1) ret=ret*base;
        base=base*base;
        b>>=1;
    }
}
void work() {
    for(int i=0;i<m;i++) { 
        cnt[i]++; 
        vis[a[i+1]]=i+1;
        if(i+1!=m) {base.x[i][i+1]++;}
        int tp=i;
        while(nxt[tp]) {
            tp=nxt[tp];
            if(vis[a[tp+1]]!=i+1) {
            vis[a[tp+1]]=i+1;
            cnt[i]++;
            base.x[i][tp+1]++;
            }
        }
        if(vis[a[1]]!=i+1) {
            cnt[i]++;
            base.x[i][1]++;
        }
        base.x[i][0]+=(10-cnt[i]);
    } 
    for(int i=0;i<m;i++)
        for(int j=0;j<m;j++) 
            if(i==j) ret.x[i][j]=1;
    ksm(n);
    ans=0;
    for(int i=0;i<m;i++) 
    (ans+=ret.x[0][i])%=p;
    printf("%d\n",ans);
}
int main()
{
    input();
    make_nxt(a,nxt);
    work();
    return 0;
}

变化

GT考试

10/26/2015

  • 加局限性示例(相等性 & 获取关联值)
  • 搭 Erica Sadun 的关联枚举示例

 

10/22/2015

  • 合并来自 #6
    @mabidakun的PR
  • 追加枚举底层的链接
  • 用帐号示例拆分为少独再次爱懂的片段。

6.BZOJ 1855
[SCOI2010]股票交易

10/21/2015

  • 合并来自 #4
    @blixt和#2
    @kandelvijayavolare和#3
    @sriniram以及#5
    @SixFiveSoftware的PR
  • 呢帐号示例添加调用代码
  • 增加 ErrorType 示例

当某位学长的博客里看到就书第一句话是省选怎么会考这么简单的题呢,然后就是发现自己不见面召开。。。

解释

<a name=”c1″></a>

  • 1、可以利用一些稍稍技巧来齐这目的,具体的请求参见下的文章内容
    <a name=”c2″></a>

  • 2、为了演示的由来,这个示例的落实经过的简化。在真的开支被,应该使可选类型以及反向顺序的参数。可以参照一下现死盛的函数式编程库,如
    Swiftz

    Dollar
    <a name=”c3″></a>

  • 3、这个示例直接使用了Swift
    官方文档的以身作则
    <a name=”c4″></a>

  • 4、经常令他们定义之职位很不便被发觉
    <a name=”c5″></a>

  • 5、这是一个简化版的,当然,Swift 为我们加以了不少的语法糖
    <a name=”c6″></a>

  • 6、如果你在动用被使用了 JSON,应该吗已经碰到了此题目
    <a name=”c6″></a>

  • 7、顺便一提,不可知直接运用数字开吗枚举 case 的称呼,因此直行使 400
    是颇的
    <a name=”c8″></a>

  • 8、虽然这样,不过支持 Mac 版的 R.swift 好像就是趁早生产了
    <a name=”c9″></a>

  • 9、这句话可以解释为: 打开链接,并初步阅读文章

神奇的乏味队列优化,可能是自身单调队列写得极其少了。。

坏爱掌握状态dp[i][j]表示时间吗i手中股票吗j的顶酷收益,初始化为极其小价,dp[0][0]=0;

然后换分三种植

不请不售:dp[i][j]=max(dp[i][j],dp[i-1][j]);

买入:dp[i][j]=max(dp[i][j],dp[i-w-1][j-k]-k*ap[i]);

卖出:dp[i][j]=max(dp[i][j],dp[i-w-1][j+k]+k*bp[i]);

然后我们发现后少独枚举k会超时,就拿它们优化一下
(其实我吗。。比较懵逼)

买入:dp[i][j]=max(dp[i][j],dp[i-w-1][k]-(j-k)*ap[i]);

                   
=max(dp[i][j],(dp[i-w-1][k]+k*ap[i])-j*ap[i]);

卖出:dp[i][j]=max(dp[i][j],dp[i-w-1][k]+(k-j)*bp[i]);

                   
 =max(dp[i][j],(dp[i-w-1][k]+k*ap[i])-j*bp[i]);

以买为例,我们发现 这无异有的
dp[i-w-1][k]+k*ap[i]
(j-k>0,j-k<as[i])具有单调性,

                   k>j-as[i]
我们枚举k,然后丢进单调队列, 更新现在之dp[i][k];

mobile.365-838.com 11mobile.365-838.com 12

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn=2000+299; 
int ans,n,maxp,w,dp[maxn][maxn];
int ap[maxn],bp[maxn],as[maxn],bs[maxn],que[maxn],ql=1,qr;
int main()
{
    scanf("%d%d%d",&n,&maxp,&w);
    for(int i=1;i<=n;i++) 
    scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]);
    memset(dp,128,sizeof(dp));
    dp[0][0]=0;
    for(int i=1;i<=n;i++) {
        ql=1,qr=0;
        for(int j=0;j<=maxp;j++) {
            dp[i][j]=max(dp[i][j],dp[i-1][j]);
            if(i-w-1>0) {
                while(ql<=qr&&que[ql]<j-as[i]) ql++;
                while(ql<=qr&&dp[i-w-1][que[qr]]+que[qr]*ap[i]-j*ap[i]<=dp[i-w-1][j]) qr--;
                que[++qr]=j;
                if(ql<=qr) dp[i][j]=max(dp[i][j],dp[i-w-1][que[ql]]+que[ql]*ap[i]-j*ap[i]);
            }
            else if(j<=as[i]) dp[i][j]=max(dp[i][j],-ap[i]*j);
        }
        ql=1,qr=0;
        for(int j=maxp;j>=0;j--) {
           if(i-w-1>0){
               while(ql<=qr&&que[ql]>j+bs[i]) ql++;
               while(ql<=qr&&dp[i-w-1][que[qr]]+que[qr]*bp[i]-j*bp[i]<=dp[i-w-1][j]) qr--;
               que[++qr]=j;
               if(ql<=qr) dp[i][j]=max(dp[i][j],dp[i-w-1][que[ql]]+que[ql]*bp[i]-j*bp[i]);
           }
        }
    }
    for(int i=0;i<=maxp;i++) ans=max(ans,dp[n][i]);
    printf("%d\n",ans);
    return 0;
}

股票交易

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 mobile.365-838.com 版权所有