2014年8月23日星期六

hdu 1875 畅通工程再续 - 若忆_star

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
hdu 1875 畅通工程再续 - 若忆_star  阅读原文»

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1875

畅通工程再续

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 15473 Accepted Submission(s): 4791


Problem Description
相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组RPRush对百岛湖的情况充分了解后,决定在符合条件的小岛间建上桥,所谓符合条件,就是2个小岛之间的距离不能小于10米,也不能大于1000米。当然,为了节省资金,只要求实现任意2个小岛之间有路通即可。其中桥的价格为 100元/米。

Input
输入包括多组数据。输入首先包括一个整数T(T <= 200),代表有T组数据。
每组数据首先是一个整数C(C <= 100),代表小岛的个数,接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。

Output
每组输入数据输出一行,代表建桥的最小花费,结果保留一位小数。如果无法实现工程以达到全部畅通,输出”oh!”.

Sample Input
2
2
10 10
20 20
3
1 1
2 2
1000 1000

Sample Output
1414.2
oh!
题目大意:要找最小的花费,那么也就可以理解为最短的路就一定为最少花费了,这里多一个的限制条件多注意一下就好了。。就是2个小岛之间的距离不能小于10米,也不能大于1000米。注意是不大于和不小于!!!
因为这里有限制条件,所以要使所有的路都连通,就需要标记一下,来看是否所有的路都走过~标记方法有很多,代码供参考。
1 #include<iostream>
2 #include<cstdio>
3 #include<cmath>
4 using namespace std;
5 double map[1010][1010],node[1010],s,Min;
6 int m,flag;
7 const double INF=999999;
8
9 void prim()
10 {
11 int vis[1010]= {0};
12 int tm=1,v=1;
13 flag=0;
14 s=0;
15 vis[tm]=1;
16 node[tm]=0;
17 for (int k=1; k<=m; k++)
18 {
19 Min=INF;
20 for (int i=1; i<=m; i++)
21 if (!vis)
22 {
23 //cout<<node<<" "<<map[tm]<<endl;
24 if(node>map[tm]&&map[tm]>=10&&map[tm]<=1000)
25 node=map[tm];
26 if (Min>node)
27 {
28 Min=node;
29 v=i;
30
31 }
32 }
33 //s+=node[v];
34 vis[v]=1;
35 tm=v;
36 }
37 for (int i=1; i<=m; i++)
38 {
39 s+=node;
40 if (node!=INF)
41 flag++;
42 }
43 }
44
45 int main ()
46 {
47 int n,a[1010],b[1010];
48 cin>>n;
49 while (n--)
50 {
51 //memset (map,INF,sizeof (map));
52 cin>>m;
53 for (int i=1; i<=m; i++)
54 {
55 cin>>a>>b;
56 }
57 for(int i=【代码优化】调用optional delegates的最佳方法 - NSTopGun  阅读原文»

【转载请注明出处】http://www.cnblogs.com/lexingyu/p/3932475.html

本文是以下两篇blog的综合脱水,感谢两位作者为解放码农生产力所做的深入思考=。=
Smart Proxy Delegation
Elegant Delegation

使用delegate的情境通常是这样

定义class和delegate

@protocol TestObjectDelegate <NSObject>
@optional
- (void)testObjectMethod;
- (NSString *)testObjectMethodWithReturnValue;

@end


@interface TestObject : NSObject

@property (nonatomic, weak) id<TestObjectDelegate> delegate;

- (void)print;
- (void)printWithLog;

@end

在类的内部调用delegate的方法

- (void)print
{
//call the delegate to do the real work
}


调用的方法通常有以下两种

普通青年:

if ([self.delegate respondsToSelector:@selector(testObjectMethod)])
{
[self.delegate testObjectMethod];
}

这个办法的缺点是
1)引入了大量glue code,每个optional function都需要3行代码。尤其在开启clang的-Warc-repeated-use-of-weak时,多次使用self.delegate(通常情况下,是weak)会被警告;

所以很可能还得这么写

- (void)print
{
id <TestObjectDelegate> delegate = self.delegate;
if ([delegate respondsToSelector:@selector(testObjectMethod)])
{
[delegate testObjectMethod];
}
}

2)调用的方法名需要写两次,很可能写错导致方法未被调用;
3)对于高频率调用的方法而言,意味着需要反复调用respondToSeletor,性能上有所影响(RunTime可能会对respondToSeletor进行缓存,因此在大部分应用上这一点不需要计入考量)。

文艺青年
先添加flag

@interface TestObject : NSObject
{
struct
{
unsigned int respond2TestObjectMethod:1;
}_flags;
}

@property (nonatomic, weak) id<TestObjectDelegate> delegate;

- (void)print;

@end

再重载setDelegate以设置flag,将respondToSeletor的结果缓存起来

- (void)setDelegate:(id<TestObjectDelegate>)delegate
{
_delegate = delegate;

BOOL respond2TestObjectMethod = [delegate respondsToSelector:@selector(testObjectMethod)];
_flags.respond2TestObjectMethod = respond2TestObjectMethod ? 1 : 0;
}

最后在print中直接使用缓存的结果

- (void)print
{
if (_flags.respond2TestObjectMethod)
{
[self.delegate testObjectMethod];
}
}

这个方法被Apple广泛采用,在SDK中随处可见。
它的优点是将respondToSeletor的结果手动缓存了起来,不需要做性能上的猜测,同时避开了
-Warc-repeated-use-of-weak的警告。
但遗憾的是,代码的冗余并没有被移除,反而更为严重(调用时仍然需要3行glue code,且在头文件和setDelegate中添加了大量代码)。当delegate中的方法名需要变动时,需要同时修改多处代码,真如噩梦一般。

嗯。。。。。。抱歉这里没有二逼青年

外国友人的想法

实际上我们真正想要的是类似于这样的东西

- (void)print
{
[self.delegateProxy testObjectMethod];
}

把glue code也好,其他额外处理也好,都放到一个统一的地方。在调用的时候,一句话简单明了,解决问题。
那么具体怎么做呢?
其实,OC的方法调用,或者准确地说,消息传递,就是这样一种机制。这里上一张自绘的图以便说明

OC中任何一次方法调用,都会从1开始走这个流程,一个步骤不行就进行下一步。若所有4个步骤走完仍然无法找到对应的impletation,则触发异常,程序crash。简单说一下各个步骤的作用
1)在类的方法表(methodList)中,根据seletor查找对应的impletation;
2) resolveInstanceMethod用于集中处理类中一些类似的方法,比如在使用core ,它们的setter和getter就可以集中在这个方法里做;
3)forwardingTargetForSelector,作用是将本对象无法处理的调用信息转给另一个对象处理,但不改变调用信息;
4)forwardInvocation,作用是根据methodSignatureForSelector和调用参数等信息生成的NSInvocation来指定一个对象处理本次调用,在指定时可以对调用信息做任意的修改,比如增加参数个数。

3被称为Fast message forwarding,相应地4则是Regular message forwarding,二者合在一起才是完整的Message forwarding

C语言在调用函数时,需要知道函数的原型,以便将参数放入寄存器或压入栈中,并视情况预留返回值的空间。OC作为C语言的超集,也需要顾及这一点。函数的调用信息在OC中以NSMethodSignature的形式存在,在Regular message forwarding中由methodSignatureForSelector返回。

从以上说明不难看出,1和2的作用是在类内部寻找impletation,而3和4则是在类外部寻找合适的其他类的实例来处理调用信息。显而易见,3和4正是delegateProxy所需要的。

铺垫了这么多,终于到了正题。

用Message forwarding机制,来构建一个delegateProxy

在这里构建了一个NSProxy的派生类作为delegateProxy,像这样

@interface CDDelegateProxy : NSProxy

@property (nonatomic, weak, readonly) id delegate;
@property (nonatomic, strong, readonly) Protocol *protocol;
@property (nonatomic, strong, readonly) NSValue *defaultReturnValue;

@end

delegateProxy中分别保存了被代理的delegate对象、delegate对应的protocol和方法未找到时提供的默认值。
在.m文件中,首先将glue code放入,像这样

//供外部需要时使用
- (BOOL)respondsToSelector:(SEL)selector
{
return [_delegate respondsToSelector:selector];
}

//Fast message forwarding, 存放glue code
- (id)forwardingTargetForSelector:(SEL)selector
{
id delegate = _delegate;
return [delegate respondsToSelector:selector] ? delegate : self;
}

嗯。。。至此似乎就完事了=。=
大部分情况下确实如此。但当方法不存在又需要一个默认返回值时,比如

- (void)printWithLog
{
//这里已经用上delegateProxy了,哈哈
NSString *logInfo = [self.delegateProxy testObjectMethodWithReturnValue];
NSLog(@"%@", logInfo);
}

就需要用到Regular message forwarding了。具体做法如下

//Regular message forwarding
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
id delegate = _delegate;
NSMethodSignature *signature = [delegate methodSignatureForSelector:selector];

//若delegate未实现对应方法,则从protocol的声明中获取MethodSignature
if (!signature)
{
if (!_signatures) _signatures = [self methodSignaturesForProtocol:_protocol];
signature = CFDictionaryGetValue(_signatures, selector);
}

//此处如果return nil, 则不会触发forwardInvocation
return signature;
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
//若默认返回值和invocation中指定的返回值一致,则取默认返回值
if (_defaultReturnValue
&& strcmp(_defaultReturnValue.objCType, invocation.methodSignature.methodReturnType) == 0)
{
char buffer;
[_defaultReturnValue getValue:buffer];
;
}
}

首先由methodSignatureForSelector根据protocol中的方法声明,返回一个signature,再由forwardInvocation判断与默认的返回值是否类型一致,一致则返回预设的默认值(即刚才提到的defaultReturnValue)。

这样,delegateProxy就构建完毕了。在使用的时候,应注意delegateProxy的作用只是在类内部保持调用的简洁,对于外部代码而言,它应该是透明的。具体来说,首先应该将deleagteProxy定义在class extension中

//.m文件中
@interface SomeObject ()<TestObjectDelegate>

@property (nonatomic, strong) id<TestObjectDelegate> delegateProxy;

@end

这里将delegateProxy直接声明为id的形式,目的是使之后编码时仍然能够享有Xcode对protocol中方法的自动提示补全。
接着override delegate(真正id被定义在头文件中)

- (void)setDelegate:(id <TestObjectDelegate>)delegate
{
self.delegateProxy = delegate ? (id <TestObjectDelegate>)[[CDDelegateProxy alloc] initWithDelegate:delegate] : nil;
}
- (id <TestObjectDelegate>)delegate
{
return ((CDDelegateProxy *)self.delegateProxy).delegate;
}

这个步骤看着有些繁琐,可以通过宏来简化,比如

#define CD_DELEGATE_PROXY_CUSTOM(protocolname, GETTER, SETTER) \
- (id<protocolname>)GETTER { return ((PSTDelegateProxy *)self.GETTER##Proxy).delegate; } \
- (void)SETTER:(id<protocolname>)delegate { self.GETTER##Proxy = delegate ? (id<protocolname>)[[PSTDelegateProxy alloc] initWithDelegate:delegate conformingToProtocol:@protocol(protocolname) defaultReturnValue:nil] : nil; }

#define CD_DELEGATE_PROXY(protocolname) PST_DELEGATE_PROXY_CUSTOM(protocolname, delegate, setDelegate)

在使用的使用可以简单地

CD_DELEGATE_PROXY(id <PSPDFResizableViewDelegate>)

当然,对于比较个性化的delegate的名称,可以通过扩展这个宏来实现。

如此一来,外部访问delegate时,获取到的仍然是正确的对象。
以上,就是调用optional delegates的最佳方法,从起因到原理到解决方案的完整阐述。

文中为便于说明,使用了我自己写的一个简化版的delegateProxy,这里提供一?p>阅读更多内容

没有评论:

发表评论