题意:目前有一部分可用内存,分为m个大小固定的区域。现有n个程序要执行,每个程序在不同大小的内存中运行所需的时间不同,要使运行完所有程序所耗时最少,问每个程序在哪块区域中从什么时间运行到什么时间,以及运行完所有程序的平均周转时间。

思路:各种记录有点麻烦!

  m个区域看成m台内存大小为该区域大小的计算机,然后n个程序分别要选择在其中一台计算机中运行。由于运行有先后顺序,这也很影响平均周转时间,所以最极端时,其中某台计算机可能有n个程序要运行,那么每台计算机就得有n个位置供挑选。所以一共有n*m个位置啦,而只有n个程序,所以左边有n个点,右边有n*m个点,这样可以用KM算法求最佳匹配(必须最佳),而因为我们要使得周转时间少,所以建图时可以将边取相反数。

  例如一台计算机:设有k个程序运行在该机,则其运行时间分别为t1,t2……tk,则第i个程序结束时间Ti=t1+t2+……+ti (因为它得等前面的人运行完),则此机器上所有程序运行时间之和为sum=k*t1 + (k-1)*t2 + (k-2)*t3 + …… + 1*tk。对于倒数第p个执行的程序c来说,其对总运行时间的贡献为p*tc(tc该程序在该机器中所需的运行时间)。其他机器也是这样的。

  那么可以建图了,如果程序c能在该机器x上运行,必定有一个运行时间t,而c可能排在任意一个位置,所以c应该有边连到机器x上的任意一个倒数为p的位置,权值为-t*p。这样子求KM的最佳匹配就行了。记得将点数少的放在左边的集合中。

  输出才是个技术活!要特别注意的是大小的问题,n<=50,m<=10。

  1. #include <bits/stdc++.h>
  2. #define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
  3. #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
  4. #define pii pair<int,int>
  5. #define INF 0x7f7f7f7f
  6. #define LL long long
  7. using namespace std;
  8. const int N=;
  9. const int M=;
  10. vector<int> vect[N];
  11. struct node
  12. {
  13. int from, to, w;
  14. node(){};
  15. node(int from,int to,int w ):from(from),to(to),w(w){};
  16. }edge[N*M*M];
  17.  
  18. struct node1
  19. {
  20. int region; //第几个区域
  21. int countdown; //倒数第几
  22. node1(){};
  23. node1(int re,int cd ):region(re),countdown(cd){};
  24. }pos[N*M] ;
  25.  
  26. int edge_cnt, pos_cnt;
  27. int m, n;
  28. int msize[N]; //m块区域
  29. int k[N], req[N][M][]; //m个程序的要求
  30.  
  31. void add_edge(int from,int to,int w)
  32. {
  33. edge[edge_cnt]=node(from, to, w);
  34. vect[from].push_back(edge_cnt++);
  35. }
  36. void add_pos(int r,int cd)
  37. {
  38. pos[pos_cnt]=node1(r,cd);
  39. pos_cnt++;
  40. }
  41.  
  42. int Lx[N], Ly[N*M], slack[N*M];
  43. int girl[N*M], S[N], T[N*M];
  44. int get_time(int p,int siz) //在reg区域找到能运行siz大小内存的时间
  45. {
  46. int t=;
  47. for(int r=; r<=k[p]; r++)
  48. {
  49. if( siz>=req[p][r][] ) t=req[p][r][];
  50. else break;
  51. }
  52. return t;
  53. }
  54. int last[N][M];
  55.  
  56. void build()
  57. {
  58. //共n*m个位置.
  59. for(int j=; j<=m; j++) //对于每块区域
  60. for(int r=; r<=n; r++) //每个位置(倒数的)
  61. add_pos(j, r);
  62.  
  63. for(int i=; i<=n; i++) //每个程序
  64. {
  65. for(int j=; j<=m; j++) //每块区域
  66. {
  67. int t=get_time(i, msize[j] );
  68. if(!t) continue; //此程序不可在此区域运行。
  69. for(int r=; r<=n; r++) //每个位置
  70. add_edge(i, (j-)*n+r, -t*r );
  71. last[i][j]=t; //记录i程序在第j区域中的运行时间
  72. }
  73. }
  74. }
  75.  
  76. bool DFS(int x)
  77. {
  78. S[x]=true;
  79. for(int j=; j<vect[x].size(); j++)
  80. {
  81. node &e=edge[vect[x][j]];
  82. if(T[e.to]) continue;
  83.  
  84. int tmp=Lx[x] +Ly[e.to] -e.w;
  85. if(tmp==)
  86. {
  87. T[e.to]=true;
  88. if(!girl[e.to] || DFS( girl[e.to] ) )
  89. {
  90. girl[e.to]=x;
  91. return true;
  92. }
  93. }
  94. else if(slack[e.to]>tmp) slack[e.to]=tmp;
  95. }
  96. return false;
  97. }
  98.  
  99. void KM() //用n个程序,匹配n*m个位置
  100. {
  101. //初始化
  102. memset(girl, , sizeof(girl));
  103. memset(Ly, , sizeof(Ly)); //数量比较大
  104. for(int i=; i<=n; i++)
  105. {
  106. Lx[i]=-INF;
  107. for(int j=; j<vect[i].size(); j++) //n*m个位置要匹配
  108. {
  109. node &e=edge[vect[i][j]];
  110. Lx[i]=max(Lx[i], e.w ); //取最大的一条边
  111. }
  112. }
  113.  
  114. for(int i=; i<=n; i++)
  115. {
  116. for(int j=n*m; j>; j--) slack[j]=INF;
  117. while(true)
  118. {
  119. memset(T, , sizeof(T));
  120. memset(S, , sizeof(S));
  121. if(DFS(i)) break;
  122.  
  123. //找最小slack
  124. int d=INF;
  125. for(int j=; j<pos_cnt; j++)
  126. if(!T[j] && d>slack[j])
  127. d=slack[j];
  128.  
  129. //更新S
  130. for(int j=; j<=n; j++)
  131. if(S[j]) Lx[j]-=d;
  132.  
  133. //更新T
  134. for(int j=; j<pos_cnt; j++)
  135. if(T[j]) Ly[j]+=d;
  136. else slack[j]-=d;
  137. }
  138. }
  139. }
  140.  
  141. inline int cmp(pii a, pii b){return a.second>b.second;}
  142. int program[N][];
  143. vector<pii> region[M];
  144. void print(int Case)
  145. {
  146. memset(program, , sizeof(program));
  147. for(int i=; i<=m; i++) region[i].clear();
  148.  
  149. for(int i=; i<pos_cnt; i++) //将匹配对的信息绑定在一起
  150. if(girl[i]!=)
  151. region[ pos[i].region ].push_back(make_pair( girl[i], pos[i].countdown ));
  152.  
  153. for(int i=; i<=m; i++) //排个序,先执行的在前
  154. sort(region[i].begin(), region[i].end(), cmp);
  155.  
  156. double sum=0.0;
  157. for(int i=; i<=m; i++) //计算执行的时间
  158. {
  159. int now=;
  160. for(int j=; j<region[i].size(); j++)
  161. {
  162.  
  163. pii a=region[i][j];
  164. program[a.first][]=i;
  165.  
  166. program[a.first][]=now;
  167. now+=last[a.first][i]; //所需要的时间呢?
  168. program[a.first][]=now;
  169.  
  170. sum+=now; //累加时间
  171. }
  172. }
  173.  
  174. if(Case>) printf("\n");
  175. printf("Case %d\n", Case);
  176. printf("Average turnaround time = %.2f\n", sum/n);
  177. for(int i=; i<=n; i++)
  178. {
  179. printf("Program %d runs in region %d from %d to %d\n", i, program[i][], program[i][], program[i][] );
  180. }
  181. }
  182.  
  183. int main()
  184. {
  185. freopen("input.txt", "r", stdin);
  186. int Case=;
  187. while(scanf("%d%d",&m,&n), n+m)
  188. {
  189. edge_cnt=pos_cnt=;
  190. for(int i=; i<=n; i++) vect[i].clear();
  191.  
  192. for(int i=; i<=m; i++) scanf("%d", &msize[i]); //m个区域的大小
  193. for(int i=; i<=n; i++) //程序i的内存要求,及时间。
  194. {
  195. scanf("%d", &k[i]);
  196. for(int j=; j<=k[i]; j++)
  197. scanf("%d %d", &req[i][j][], &req[i][j][]);
  198. }
  199. build(); //建图
  200. KM(); //最佳匹配
  201. print(++Case);//输出
  202. }
  203. return ;
  204. }

AC代码

UVALive 2238 Fixed Partition Memory Management 固定分区内存管理(KM算法,变形)的更多相关文章

  1. UVALive 2238 Fixed Partition Memory Management(二分完美匹配)

    题意:计算机中有一些固定大小的内存,内存越大,处理速度越快.对于一个程序,加入不同的内存空间,处理所需时间不同.现给出m个内存空间,n个程序,对于每个程序程序,有k组数据(s,t),分别表示当程序 i ...

  2. Fixed Partition Memory Management UVALive - 2238 建图很巧妙 km算法左右顶点个数不等模板以及需要注意的问题 求最小权匹配

    /** 题目: Fixed Partition Memory Management UVALive - 2238 链接:https://vjudge.net/problem/UVALive-2238 ...

  3. LA2238 Fixed Partition Memory Management

    题目大意: m(m<=10)个内存区域,n(n<=50)个程序.找出一个方案来,使得平均结束时刻尽量小.题目保证有解. 同一个程序运行在不同大小的内存区域内,其运行时间不同.(注意,这里说 ...

  4. 【LA2238 训练指南】固定分区内存管理 【二分图最佳完美匹配,费用流】

    题意 早期的多程序操作系统常把所有的可用内存划分为一些大小固定的区域,不同的区域一般大小不同,而所有区域的大小之和为可用内存的大小.给定一些程序,操作系统需要给每个程序分配一个区域,使得他们可以同时执 ...

  5. UVALive 4043 Ants 蚂蚁(二分图最佳完美匹配,KM算法)

    题意: 有n个蚂蚁n棵树,蚂蚁与树要配对,在配对成功的一对之间连一条线段,要求所有线段不能相交.按顺序输出蚂蚁所匹配的树. 思路: 这个题目真是技巧啊,不能用贪心来为每个蚂蚁选择最近的树,这样很可能是 ...

  6. Memory Management in Open Cascade

    Open Cascade中的内存管理 Memory Management in Open Cascade eryar@163.com 一.C++中的内存管理 Memory Management in ...

  7. 如何展开Linux Memory Management学习?

    Linux的进程和内存是两座大山,没有翻过这两座大山对于内核的理解始终是不完整的. 关于Linux内存管理,在开始之前做些准备工作. 首先bing到了Quora的<How can one rea ...

  8. Operating System Memory Management、Page Fault Exception、Cache Replacement Strategy Learning、LRU Algorithm

    目录 . 引言 . 页表 . 结构化内存管理 . 物理内存的管理 . SLAB分配器 . 处理器高速缓存和TLB控制 . 内存管理的概念 . 内存覆盖与内存交换 . 内存连续分配管理方式 . 内存非连 ...

  9. Lifetime-Based Memory Management for Distributed Data Processing Systems

    Lifetime-Based Memory Management for Distributed Data Processing Systems (Deca:Decompose and Analyze ...

随机推荐

  1. cassandra在服务端像leveldb一样进行插入初试成功

    经过研究,决定在 cql3/QueryProcessor.java 里面下手. 这里有两个函数,第一个是 public ResultMessage process(String queryString ...

  2. 禁止屏幕旋转并同时解决以至于导致Activity重启的方法

    1.禁止屏幕旋转在AndroidManifest.xml的每一个需要禁止转向的Activity配置中加入android:screenOrientation属性. //landscape(横向)port ...

  3. 礼物gift(DP)

    这道题的DP非常的有意思…… 一开始我们总是会以为这是一个背包问题,直接dp[0] = 0,dp[j] += dp[j-c[i]]进行转移.之后统计一下从dp[m-minn]~dp[m]的答案之和为结 ...

  4. java服务器端断点续传

    Servlet Java代码 复制代码 收藏代码 import java.io.BufferedOutputStream; import java.io.File; import java.io.IO ...

  5. Python学习之旅—生成器与迭代器案例剖析

    前言 前面一篇博客笔者带大家详细探讨了生成器与迭代器的本质,本次我们将实际分析一个具体案例来加深对生成器与迭代器相关知识点的理解. 本次的案例是一个文件过滤操作,所做的主要操作就是过滤出一个目录下的文 ...

  6. vim的visual可视模式(转载)

    转自:http://www.cnblogs.com/chenyadong/archive/2011/08/30/2159809.html 为了便于选取文本,VIM 引入了可视(Visual)模式.要选 ...

  7. J20170507-ts

    プロンプト n. 提示 オブジェクト n. 对象 アスタリスク *  アンパサンド      & スラッシュ       / イテレータ    n 迭代器 差し詰め 当前 スペル spell ...

  8. C++笔试题库之编程、问答题 100~150道

    101. winsock建立连接的主要实现步骤? 答: 服务器端:socket()建立套接字,绑定(bind)并监听(listen),用accept()等待客户端连接, accept()发现有客户端连 ...

  9. python property的2种使用方法

    一.property类 class Person(): def __init__(self, name): self.set_name(name) def get_name(self): return ...

  10. 【CodeForces - 651C 】Watchmen(map)

    Watchmen 直接上中文 Descriptions: 钟表匠们的好基友马医生和蛋蛋现在要执行拯救表匠们的任务.在平面内一共有n个表匠,第i个表匠的位置为(xi, yi). 他们需要安排一个任务计划 ...