UVALive2238 Fixed Partition Memory Management

这道题本来很水,但无奈官方数据出错,标程都wa了(后来数据恢复了),让我白忙了2小时,有点难过55...

最后在UVA1006上才交过了= =!

算法思路是:

对于一个内存块x,在里面运行的程序的运行时间为t1, t2, t3, ..., tk,那么第i个程序的结束时间为 ri = t1+ t2 + ... + ti,对于所有在这个内存块运行的程序的结束时间总和为 r=k * t1 + (k - 1) * t2 +...+ 1 * tk

我们可以发现,程序k是内存块x的倒数第p个执行的程序,那么对于最后结果的影响为:t = p * Tk,x(Tk,x为程序k在内存块x的运行时间)

那么我们就可以构造二分图:左边的节点为n个程序;右边的节点为n * m个节点,对于(i, j)表示第i个内存块运行的倒数第j个程序,然后就可以与n个程序连上一条边权为:p * Tj,i 的边。然后套上KM算法模板即可。

剩下的细节就不讨论了...

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 500;
const int INF = INT_MAX;

struct edge {
    int u, v, wt;
};

struct node {
    int S, T;
    bool operator < (const node &rhs)   const   {
        return S < rhs.S;
    }
};

int n, m;
int Size[MAXN + 10];
vector<node> A[MAXN + 10];
int res[MAXN + 10];

int work_time(vector<node> &pro, int blo) {
    if(pro.size() == 0) return 0;
    if(Size[blo] < pro[0].S)    return INF;
    int tmp = upper_bound(pro.begin(), pro.end(), (node){Size[blo], 0}) - pro.begin() - 1;
    return pro[tmp].T;
}

struct KM_algorithm {
    vector<int> G[MAXN + 10];
    vector<edge> Edge;

    int Lx[MAXN + 10], Ly[MAXN + 10], Slack[MAXN + 10];
    int nx, ny, Left[MAXN + 10];
    bool S[MAXN + 10], T[MAXN + 10];

    void init(int nx, int ny) {
        this->nx = nx, this->ny = ny;
        for(int u = 1; u <= nx; u++)
            G[u].clear();
        Edge.clear();
    }

    void Addedge(int u, int v, int wt)  {
        Edge.push_back((edge){u, v, wt});
        G[u].push_back(Edge.size() - 1);
    }

    bool match(int u)    {
        S[u] = 1;
        for(int i = 0; i < G[u].size(); i++)    {
            edge &e = Edge[G[u][i]];
            if(!T[e.v]) {
                int t = Lx[e.u] + Ly[e.v] - e.wt;
                if(t == 0)  {
                    T[e.v] = 1;
                    if(!Left[e.v] || match(Left[e.v]))  {
                        Left[e.v] = e.u;
                        return 1;
                    }
                }
                Slack[e.v] = min(Slack[e.v], t);
            }
        }
        return 0;
    }

    void Update()   {
        int i, a = INF;
        for(i = 1; i <= ny; i++)
            if(!T[i])   a = min(a, Slack[i]);
        for(i = 1; i <= ny; i++)   {
            if(S[i])    Lx[i] -= a;
            if(T[i])    Ly[i] += a;
            else Slack[i] -= a;
        }
    }

    int KM()    {
        int i, ans = 0;

        for(i = 1; i <= ny; i++)
            Lx[i] = Ly[i] = Left[i] = 0;

        for(i = 1; i <= nx; i++) {
            memset(Slack, 0x3f, sizeof(Slack));
            while(1)    {
                memset(S, 0, sizeof(S));
                memset(T, 0, sizeof(T));
                if(match(i))    break;
                else Update();
            }
        }

        for(i = 1; i <= ny; i++)    {
            ans += Lx[Left[i]] + Ly[i];
        }
        return -ans;
    }

}   sp;

void Read_input()   {
    sp.init(n, m * n);
    for(int i = 1; i <= m; i++)
        scanf("%d", &Size[i]);
    for(int i = 1, c; i <= n; i++) {
        scanf("%d", &c);
        A[i].clear();

        for(int j = 1; j <= c; j++) {
            node t;
            scanf("%d%d", &t.S, &t.T);
            A[i].push_back(t);
        }

        for(int j = 1; j <= m; j++) {
            int tmp = work_time(A[i], j);
            if(tmp == INF)  continue;

            for(int k = 1; k <= n; k++)
                sp.Addedge(i, (j - 1) * n + k, -k * tmp);
        }
    }
}

int Start[MAXN + 10];

void work() {
    int ans = sp.KM();
    printf("Average turnaround time = %.2lf\n", 1.0 * ans / n);

    for(int i = 1; i <= m; i++) {
        for(int j = n; j >= 1; j--) {
            int v = (i - 1) * n + j;
            if(sp.Left[v])  {
                res[sp.Left[v]] = i;
                int Last = j == n ? 0 : sp.Left[v + 1];
                int tmp = work_time(A[Last], i);
                Start[sp.Left[v]] = tmp + Start[Last];
            }
        }
    }
    for(int i = 1; i <= n; i++) {
        printf("Program %d runs in region %d from %d to %d\n", i, res[i], Start[i], Start[i] + work_time(A[i], res[i]));
    }
}

int main()  {
    int kase = 0;

    while(scanf("%d%d", &m, &n) == 2 && (n || m))   {
        Read_input();
        printf("Case %d\n", ++kase);
        work();
        puts("");
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值