UVALive 2238 Fixed Partition Memory Management(建图、KM)

题目:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=239

题目大意:有m个内存空间,n个程序要跑,每个程序要跑都要一定的内存空间,所以对于每个程序,他有 k 个si、ti,si < s(i+1) ,表示如果 si<=mem < s(i+1),它的时间是 ti。如果比 s0 还要小,就是说明不能运行。让你求出调度他们的方案,使得所有程序的 平均结束时间最小。输出这个最小的平均时间和调度方案。

解题思路:假设一个内存区域,按顺序执行k个程序,时间是 t1、t2、t3 ... tk,所有程序的结束时间和是 k*t1 + (k-1)*t2 + (k-2)*t3 + ... + tk,也就是,如果在内存块 i 某个程序 i 是倒数第 p 个运行的,那么他的贡献值是p*t(i,j)。

         所以说我们构造二分图,左边是 n 个程序,右边是 n*m 个点,表示 m 个内存,倒数第 1~n 。边的权值为 p*t(i,j)。 这样建完之后就只要求最小权匹配即可。注意:并不是所有的匹配都对应一个合法方案,因为有的是只有倒数第二,没有倒数第一。但是,我们求得最佳匹配是不会出现这种情况的,肯定是合法的,因为要乘一个系数,肯定是乘越小越好,就是先有倒数第一,才会有倒数第二,看看后面的输出就知道了。

        这道题先是TLE了好久,就是不知道什么原因,后来才发现,原来后面乘系数的时候,我无法运行标的是 INF,后面系数直接拿来乘了,结果爆 int 了。。。 然后又 WA 了好久,一点一点查,才发现,是用来编号的 id 数组我开成 [ MAX_N ][ MAX_M ] 了,应该是 [ MAX_M ][ MAX_N ]。。= =

代码如下:

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

const int INF = 0x0fffffff;
const int MAX_N = 55;
const int MAX_M = 11;

int id[MAX_M][MAX_N];

int nn;
int get_id(int i,int j)
{
    if(!id[i][j]) return id[i][j] = ++nn;
    return id[i][j];
}

void get_id_init()
{
    memset(id,0,sizeof(id));
    nn = 0;
}

vector<pair<int,int> > p[MAX_N];
int mem[MAX_M];

int w[MAX_N][MAX_N*MAX_M],time[MAX_N][MAX_M];

void build(int n,int m)
{
    get_id_init();
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= m;j++)
        {
            /*if(mem[j] < p[i][0].first)
                time[i][j] = INF;
            else
            {
                int x = upper_bound(p[i].begin(),p[i].end(),make_pair(mem[j],INF))-p[i].begin();
                time[i][j] = p[i][x-1].second;
            }
            //printf("i = %d,j = %d,time = %d\n",i,j,time[i][j]);*/
            for(int k = 1;k <= n;k++)
            {
                if(time[i][j] >= INF) w[i][get_id(j,k)] = -INF;
                else w[i][get_id(j,k)] = -time[i][j]*k;
            }
        }
}

struct KM
{
    int n1,n2;
    int s[MAX_N],t[MAX_N*MAX_M],left[MAX_N*MAX_M];
    int lx[MAX_N],ly[MAX_N*MAX_M],slack[MAX_N*MAX_M];

    void init(int a,int b)
    {
        n1 = a;n2 = b;
    }

    int match(int i)
    {
        s[i] = 1;
        for(int j = 1;j <= n2;j++)
            if(!t[j])
            {
                int tmp = lx[i]+ly[j]-w[i][j];
                if(tmp == 0)
                {
                    t[j] = 1;
                    if(!left[j] || match(left[j]))
                    {
                        left[j] = i;
                        return 1;
                    }
                }
                else slack[j] = min(slack[j],tmp);
            }
        return 0;
    }

    void update()
    {
        int a = INF;
        for(int i = 1;i <= n2;i++)
            if(!t[i]) a = min(a,slack[i]);
        for(int i = 1;i <= n1;i++)
            if(s[i]) lx[i] -= a;
        for(int i = 1;i <= n2;i++)
            if(t[i]) ly[i] += a;
    }

    void solve()
    {
        for(int i = 1;i <= n1;i++)
        {
            lx[i] = -INF;
            for(int j = 1;j <= n2;j++)
                lx[i] = max(lx[i],w[i][j]);
        }
        for(int i = 1;i <= n2;i++)
            left[i] = ly[i] = 0;

        for(int i = 1;i <= n1;i++)
        {
            for(int j = 1;j <= n2;j++)
                slack[j] = INF;
            while(1)
            {
                for(int j = 1;j <= n1;j++) s[j] = 0;
                for(int j = 1;j <= n2;j++) t[j] = 0;
                if(match(i)) break;
                else update();
            }
        }
    }
}km;

int pp[MAX_N][5];

void print(int n,int m)
{
    int sum = 0;
    for(int i = 1;i <= km.n2;i++)
        if(km.left[i])
        {
            int pro = km.left[i];
            //printf("%d---%d\n",pro,i);
            sum += w[pro][i];
        }
    double avg = -sum*1.0/n;
    printf("Average turnaround time = %.2f\n",avg);
    for(int i = 1;i <= m;i++)
    {
        /*
        int cc = id[i][1];
        for(;cc <= id[i][n];cc++) if(km.left[cc] == 0) break;
        cc--;
        */
        int cc = id[i][n];
        for(;cc >= id[i][1];cc--) if(km.left[cc]) break;
        int ss = 0,tt = 0;
        for(int j = cc;j >= id[i][1];j--)
        {
            int pro = km.left[j];
            tt = ss+time[pro][i];
            pp[pro][0] = i;
            pp[pro][1] = ss;
            pp[pro][2] = tt;
            ss = tt;
        }
    }
    for(int i = 1;i <= n;i++)
        printf("Program %d runs in region %d from %d to %d\n",i,pp[i][0],pp[i][1],pp[i][2]);
    puts("");
}

int main()
{
    int cas = 0;
    int n,m;
    while(~scanf("%d%d",&m,&n) && (n+m))
    {
        for(int i = 1;i <= m;i++)
            scanf("%d",&mem[i]);
        for(int i = 1;i <= n;i++)
            for(int j = 1;j <= m;j++)
                time[i][j] = INF;
        for(int i = 1;i <= n;i++)
        {
            p[i].clear();
            int k;
            scanf("%d",&k);
            while(k--)
            {
                int s,t;
                scanf("%d%d",&s,&t);
                //p[i].push_back(make_pair(s,t));
                for(int l = 1;l <= m;l++)
                    if(mem[l] >= s) time[i][l] = t;
            }
        }
        build(n,m);
        km.init(n,nn);
        km.solve();
        printf("Case %d\n",++cas);
        print(n,m);
    }
    return 0;
}

/*
2 4
40 60
1 35 4
1 20 3
1 40 10
1 60 7

2 3
40 60
1 35 4
1 20 3
1 40 10

*/

还有要求最小权和匹配,其实我先开始的做法是模仿最大子图那样,做最小子图,即选择权值最小的边作为开始顶标,然后也是一样模仿的做,可以证明这样也行。

代码如下:

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

const int INF = 0x0fffffff;
const int MAX_N = 55;
const int MAX_M = 11;

int id[MAX_M][MAX_N];

int nn;
int get_id(int i,int j)
{
    if(!id[i][j]) return id[i][j] = ++nn;
    return id[i][j];
}

void get_id_init()
{
    memset(id,0,sizeof(id));
    nn = 0;
}

vector<pair<int,int> > p[MAX_N];
int mem[MAX_M];

int w[MAX_N][MAX_N*MAX_M],time[MAX_N][MAX_M];

void build(int n,int m)
{
    get_id_init();
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= m;j++)
        {
            if(mem[j] < p[i][0].first)
                time[i][j] = INF;
            else
            {
                int x = upper_bound(p[i].begin(),p[i].end(),make_pair(mem[j],INF))-p[i].begin();
                time[i][j] = p[i][x-1].second;
            }
            //printf("i = %d,j = %d,time = %d\n",i,j,time[i][j]);
            for(int k = 1;k <= n;k++)
            {
                if(time[i][j] >= INF) w[i][get_id(j,k)] = INF;
                else w[i][get_id(j,k)] = time[i][j]*k;
            }
        }
}

struct KM
{
    int n1,n2;
    int s[MAX_N],t[MAX_N*MAX_M],left[MAX_N*MAX_M];
    int lx[MAX_N],ly[MAX_N*MAX_M],slack[MAX_N*MAX_M];

    void init(int a,int b)
    {
        n1 = a;n2 = b;
    }

    int match(int i)
    {
        s[i] = 1;
        for(int j = 1;j <= n2;j++)
            if(!t[j])
            {
                int tmp = lx[i]+ly[j]-w[i][j];
                if(tmp == 0)
                {
                    t[j] = 1;
                    if(!left[j] || match(left[j]))
                    {
                        left[j] = i;
                        return 1;
                    }
                }
                else slack[j] = min(slack[j],abs(tmp));
            }
        return 0;
    }

    void update()
    {
        int a = INF;
        for(int i = 1;i <= n2;i++)
            if(!t[i]) a = min(a,slack[i]);
        for(int i = 1;i <= n1;i++)
            if(s[i]) lx[i] += a;
        for(int i = 1;i <= n2;i++)
            if(t[i]) ly[i] -= a;
    }

    void solve()
    {
        for(int i = 1;i <= n1;i++)
        {
            lx[i] = INF;
            for(int j = 1;j <= n2;j++)
                lx[i] = min(lx[i],w[i][j]);
        }
        for(int i = 1;i <= n2;i++)
            left[i] = ly[i] = 0;

        for(int i = 1;i <= n1;i++)
        {
            for(int j = 1;j <= n2;j++)
                slack[j] = INF;
            while(1)
            {
                for(int j = 1;j <= n1;j++) s[j] = 0;
                for(int j = 1;j <= n2;j++) t[j] = 0;
                if(match(i)) break;
                else update();
            }
        }
    }
}km;

int pp[MAX_N][5];

void print(int n,int m)
{
    int sum = 0;
    for(int i = 1;i <= km.n2;i++)
        if(km.left[i])
        {
            int pro = km.left[i];
            //printf("%d---%d\n",pro,i);
            sum += w[pro][i];
        }
    double avg = sum*1.0/n;
    printf("Average turnaround time = %.2f\n",avg);
    for(int i = 1;i <= m;i++)
    {
        int cc = id[i][1];
        for(;cc <= id[i][n];cc++) if(km.left[cc] == 0) break;
        cc--;
        int ss = 0,tt = 0;
        for(int j = cc;j >= id[i][1];j--)
        {
            int pro = km.left[j];
            tt = ss+time[pro][i];
            pp[pro][0] = i;
            pp[pro][1] = ss;
            pp[pro][2] = tt;
            ss = tt;
        }
    }
    for(int i = 1;i <= n;i++)
        printf("Program %d runs in region %d from %d to %d\n",i,pp[i][0],pp[i][1],pp[i][2]);
    puts("");
}

int main()
{
    int cas = 0;
    int n,m;
    while(~scanf("%d%d",&m,&n) && (n+m))
    {
        for(int i = 1;i <= m;i++)
            scanf("%d",&mem[i]);
        for(int i = 1;i <= n;i++)
        {
            p[i].clear();
            int k;
            scanf("%d",&k);
            while(k--)
            {
                int s,t;
                scanf("%d%d",&s,&t);
                p[i].push_back(make_pair(s,t));
            }
        }
        build(n,m);
        km.init(n,nn);
        km.solve();
        printf("Case %d\n",++cas);
        print(n,m);
    }
    return 0;
}

/*
2 4
40 60
1 35 4
1 20 3
1 40 10
1 60 7

2 3
40 60
1 35 4
1 20 3
1 40 10

*/



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值