karger算法求最小cut
cut就是指把一个图的结点分为两个集合,那么其中一些边的端点是分属两个集合的,使这种边数量最小的划分就叫minimum cut。
karger的算法是个randomnized algorithm,思路是随机找一个边,把这个边的两个端点融合为一个结点,把多余的点和边删除。
注意如果融合后的新结点出现self loop,那么是要删除这个self loop的,但是只是和其他结点形成平行边,那么这些平行边当然是不可以删除的。
最后合并到只剩两个点的时候,就相当于把原来的图的结点分为了两个集合,剩下的边就是这时的cut了。
当然这个算法正确的概率只有1/n^2,所以是需要多次重复来得到最好结果的,假设图有n个结点,那么运行n^2ln(n)次,错误概率会降为仅有1/n。
还是老问题:看着思路很简单,写起来就很烦,主要是对结点和边的操作简直要命,而且最后得到的实现也只是个o(n^2)的,见了鬼了。而且也没有很省空间,为了遍历+删除的list操作,开了很多新list,感觉蠢的要死,还是得赶紧学会fuctional programming啊。
import random def readfile(): ''' 读文件 ''' pass def randomcut(adict): ''' 生成两个随机数,返回随机数决定的两个字符串 ''' a = random.randrange(0, len(adict)) b = random.randrange(0, len(adict[list(adict.keys())[a]])) return (list(adict.keys())[a], adict[list(adict.keys())[a]][b]) def newadict(adict, vertex1, vertex2): ''' 把随机决定的那两个字符串代表的结点融合(这个模块写的简直要了老命了) ''' list1 = adict[vertex1][:] list2 = adict[vertex2][:] for i in list1: if i == vertex2: adict[vertex1].remove(i) for j in list2: if j == vertex1: adict[vertex2].remove(j) for a in adict[vertex2]: if a != vertex1 : for m in adict[a]: if m == vertex2: adict[a].remove(vertex2) adict[a].append(vertex1) adict[vertex1].append(a) adict.pop(vertex2) return adict def mincut(adict): ''' 主程序,融合到只剩两个结点的时候停止 ''' if len(adict) == 2: return (len(adict[list(adict.keys())[0]]), len(adict[list(adict.keys())[1]]), adict) else: (vertex1, vertex2) = randomcut(adict) adict2 = newadict(adict, vertex1, vertex2) return mincut(adict2) def main(): ''' 运行100次主程序,返回最小的mincut ''' templist = [] for a in range(100): adict = readfile() b = mincut(adict) temp = b[0] templist.append(temp) print(templist) print(min(templist)) main()
相关推荐
seacover 2012-10-19