题目大意:
m(m<=10)个内存区域,n(n<=50)个程序。找出一个方案来,使得平均结束时刻尽量小。题目保证有解。
同一个程序运行在不同大小的内存区域内,其运行时间不同。(注意,这里说的大小是指整个内存区域大小,而不是说:该程序之前有程序运行,占用了一部分内存,剩下的那部分内存大小。。。。。。。)
输入:m和n,然后是m个数表示内存区域大小。再是n行,每行第1个数为情况总数k(k<=10),然后是k对整数s1,t1,s2,t2……sk,tk,满足si<si+1表示在各个内存中的运行时间。
如果内存块总大小s不足s1,则无法在该内存块运行该程序;当si<=s<si+1时,运行时间为ti;当s>=sk时,运行时间为tk
输出:平均最小结束时间和调度方案。
(转自http://blog.csdn.net/u014679804/article/details/46725083)
题解:发现早运行的程序,对后面的结束时刻的影响是固定的,即某个内存区域倒数第p个,贡献为pT,T为程序在某个内存区域的运行时间。于是可以左边为程序,右边为每个内存区域倒数第几个运行,对应连边,边权为贡献,求最小权匹配。不难发现不会出现倒数第一匹配,倒数第二没匹配,倒数第三匹配的情况(何不匹配倒数第二呢?)
拍了很久,平均时间没有错,方案小数据看了很多组也没组
估计是SPJ没有或者不对。。。
网上的程序试了一个,都跟样例输出的一模一样,其他数据也都一模一样。。。
就当是对的吧。。OI一般也不会让输出方案反正。。
1 #include <cstdio> 2 #include <cstring> 3 #define max(a, b) ((a) > (b) ? (a) : (b)) 4 template<class T> 5 inline void swap(T &a, T &b) 6 { 7 T tmp = a;a = b;b = tmp; 8 } 9 inline void read(int &x) 10 { 11 x = 0;char ch = getchar(), c = ch; 12 while(ch < ‘0‘ || ch > ‘9‘) c = ch, ch = getchar(); 13 while(ch <= ‘9‘ && ch >= ‘0‘) x = x * 10 + ch - ‘0‘, ch = getchar(); 14 if(c == ‘-‘) x = -x; 15 } 16 const int INF = 0x3f3f3f3f; 17 const int MAXN = 200 + 5; 18 const int MAXM = 200 + 5; 19 int size[MAXM * MAXN], s[MAXM * MAXN], t[MAXM * MAXN], n, m, ca; 20 int g[MAXN][MAXN * MAXM], n1, n2, sla[MAXN * MAXM], pre[MAXN * MAXM], vis[MAXN * MAXM], lab1[MAXN * MAXN], lab2[MAXN * MAXM], lk1[MAXN * MAXN], lk2[MAXN * MAXM]; 21 void cal(int x) 22 { 23 memset(vis, 0, sizeof(vis)), memset(sla, 0x3f, sizeof(sla)), memset(pre, 0, sizeof(pre)), vis[0] = 1; 24 int y; 25 do 26 { 27 y = 0; 28 for(int i = 1;i <= n2;++ i) 29 { 30 if(vis[i]) continue; 31 if(lab1[x] + lab2[i] - g[x][i] < sla[i]) sla[i] = lab1[x] + lab2[i] - g[x][i], pre[i] = x; 32 if(sla[i] < sla[y]) y = i; 33 } 34 int d = sla[y]; 35 for(int i = 1;i <= n1;++ i) if(vis[lk1[i]]) lab1[i] -= d; 36 for(int i = 1;i <= n2;++ i) if(vis[i]) lab2[i] += d; else sla[i] -= d; 37 vis[y] = 1; 38 }while(x = lk2[y]); 39 for(;y;swap(y, lk1[lk2[y] = pre[y]])); 40 } 41 double KM() 42 { 43 for(int i = 1;i <= n1;++ i) cal(i); 44 int ans = 0; 45 for(int i = 1;i <= n1;++ i) ans += g[i][lk1[i]]; 46 return (double)-ans; 47 } 48 int tag[MAXN], from[MAXN], to[MAXN], stack[MAXN], tot; 49 int main() 50 { 51 52 while(scanf("%d %d\n", &m, &n) != EOF && n && m) 53 { 54 if(ca) putchar(‘\n‘); 55 memset(from, 0, sizeof(from)), memset(tag, 0, sizeof(tag)), memset(to, 0, sizeof(to)), memset(stack, 0, sizeof(stack)), n1 = n, n2 = n * m, ++ ca, memset(lab1, -0x3f, sizeof(lab1)), memset(lk1, 0, sizeof(lk1)), memset(lk2, 0, sizeof(lk2)), memset(g, -0x3f, sizeof(g)), memset(lab2, 0, sizeof(lab2)); 56 for(int i = 1;i <= m;++ i) read(size[i]); 57 for(int i = 1;i <= n;++ i)//考虑每个程序 58 { 59 int k;read(k); 60 for(int j = 1;j <= k;++ j) read(s[j]), read(t[j]); 61 s[k + 1] = INF; 62 for(int j = 1;j <= m;++ j)//在区域j中 63 for(int l = 1;l <= k;++ l) 64 if(s[l] <= size[j] && size[j] < s[l + 1])//运行时间为t[l] 65 for(int p = 1;p <= n;++ p) //倒数第p个运行 66 g[i][(j - 1) * n + p] = - p * t[l], lab1[i] = max(lab1[i], - p * t[l]); 67 } 68 printf("Case %d\nAverage turnaround time = %.2lf\n", ca, KM() / (double)n); 69 for(int i = 1;i <= n;++ i) tag[i] = (lk1[i] - 1) / n + 1; 70 for(int i = 1;i <= m;++ i) 71 { 72 tot = 0;int sum = 0; 73 for(int j = 1;j <= n;++ j) if(tag[j] == i) stack[++ tot] = j; 74 for(;tot;-- tot) 75 from[stack[tot]] = sum, to[stack[tot]] = sum = sum + (-g[stack[tot]][lk1[stack[tot]]] / ((lk1[stack[tot]] - 1) % n + 1)); 76 } 77 for(int i = 1;i <= n;++ i) printf("Program %d runs in region %d from %d to %d\n", i, tag[i], from[i], to[i]); 78 } 79 return 0; 80 }