LA 2238 - Fixed Partition Memory Management 二分匹配 World Finals >> 2001

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



 World Finals >> 2001


 

二分图:

左边结点为任务,右边结点表示 第几块内存区域的倒数第几个任务。

详见代码:



#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<climits>
#include<queue>
#include<vector>
#include<map>
#include<sstream>
#include<set>
#include<stack>
#include<cctype>
#include<utility>
#pragma comment(linker, "/STACK:102400000,102400000")
#define PI 3.1415926535897932384626
#define eps 1e-7
#define sqr(x) ((x)*(x))
#define FOR0(i,n)  for(int i=0 ;i<(n) ;i++)
#define FOR1(i,n)  for(int i=1 ;i<=(n) ;i++)
#define FORD(i,n)  for(int i=(n) ;i>=0 ;i--)
#define  lson   num<<1,le,mid
#define rson    num<<1|1,mid+1,ri
#define MID   int mid=(le+ri)>>1
#define zero(x)((x>0? x:-x)<1e-15)
#define mk    make_pair
#define _f     first
#define _s     second

using namespace std;
//const int INF=    ;
typedef long long ll;
//const ll inf =1000000000000000;//1e15;
//ifstream fin("input.txt");
//ofstream fout("output.txt");
//fin.close();
//fout.close();
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);




const ll INF =1000000000000000;
const int maxn=   50+10   ;
const int maxm=  10+3  ;
//by yskysker123
ll siz[maxm]; //maxn是任务最大数目,maxm是内存块最大数目
ll s[maxn][12];     
ll t[maxn][12];
ll cost[maxn][maxm];//[任务编号][内存编号]
int num[maxn];
int lef[maxn*maxm];
ll lx[maxn],ly[maxn*maxm];
bool S[maxn],T[maxn*maxm];
int reg[maxn];
int pri[maxn];
ll w[maxn][maxn*maxm];
int n,m;
int cnt;//表示 右边的结点数目,右边的结点[maxm][maxn]:[内存块编号][该内存块执行的倒数第几个任务]
ll ans;
ll tim[maxm][maxn];
int  work(ll si,int pth,int le,int ri)//内存块大小,任务编号,二分区域le、ri,确定该大小內存执行该任务所花时间。
{ 
    //二分,在该任物的s1之前加个s0=0,t0=INF(无穷),
  //  找到比内存块大小 小,且差值最小的si。由此确定该大小內存执行该任务所花时间
//    cout<<si<<" "<<pth<<" "<<le<<" "<<ri<<endl;
    while(le<=ri)
    {
        int mid=(le+ri)/2;
        if(   si  >=s[pth][mid]  )  le=mid+1;
        else ri=mid-1;
    }
//    cout<<"pth "<<ri<<endl;
    return ri;
}

//带权二分匹配:
bool match(int i)
{
    S[i]=true;
    for(int j=1;j<=cnt;j++)
    {
        if(lx[i]+ly[j]==w[i][j]&&!T[j])
        {
            T[j]=1;
            if(!lef[j]||match(lef[j]))
            {
                lef[j]=i;
                return true;
            }
        }
    }
    return false;
}


void update()
{
    ll a=INF;
    for(int i=1;i<=n;i++)  if(S[i])
        for(int j=1;j<=cnt;j++)  if(!T[j])
          a=min(a,lx[i]+ly[j]-w[i][j]);
    for(int i=1;i<=n;i++)
    {
       if(S[i])  lx[i]-=a;
    }
    for(int i=1;i<=cnt;i++)
    {
        if(T[i])  ly[i]+=a;

    }



}


void KM()
{
    for(int i=1;i<=n;i++)
       lx[i]=- INF;
    for(int i=1;i<=cnt;i++)
       ly[i]=lef[i]=0;

   for(int i=1;i<=n;i++)
   {
       for(int j=1;j<=cnt;j++)
       {
           lx[i]=max(lx[i],w[i][j]);

       }
//        cout<<"lx["<<i<<"]  "<<lx[i]<<endl;;
   }


    for(int i=1;i<=n;i++)
    {
        while(1)
        {
             for(int j=1;j<=n;j++)   S[j]=0;
            for(int j=1;j<=cnt;j++)  T[j]=0;
            if(match(i))  break;
            else update();

        }
    }
    memset(tim,0,sizeof tim);
    ans=0;
    for(int i=cnt;i>=1;i--)
    {
//        cout<<"y: "<<i <<endl;
         if(!lef[i])  continue; //错误写法:if(!T[i])  continue;
//       cout<<"aaaa"<<endl;
        int p=lef[i]; //任务编号
        int th=(i-1)/n  +1; //内存编号
        reg[p]= th;// 任务对应内存
        int thvp= (i-1)%n  +1;//  倒数第几个操作
//        cout<<"task :"<<p<<endl;
//        cout<<"ans add"<<endl;
//        cout<<-w[p][i]<<endl;
        ans-= w[p][i];
//        cout<<"ans = "<<ans<<endl;
        tim[th][thvp]=tim[th][thvp+1]+cost[p][th];//第th个内存区域,执行它的倒数第thvp个任务的结束时间。
        pri[p]=thvp;// 顺序编号(倒数)

    }
//    cout<<ans<<endl;

//    cout<<ans<<endl;
}


int main()
{
    int kase=0;
    while(~scanf("%d%d",&m,&n)&&(m||n))
    {
//        cout<<"region "<<m<<"program "<<n<<endl;
        for(int i=1;i<=m;i++)
        {
            
            scanf("%lld",&siz[i]);
        }
        int k;
        for(int i=1;i<=n;i++)
        {
            
            scanf("%d",&k);
            num[i]=k;
            for(int j=1;j<=k;j++)
            {
                scanf("%lld%lld",&s[i][j],&t[i][j]);
            }
            s[i][0]=0;  //方便二分
            t[i][0]=INF;//方便二分

        }



        for(int i=1;i<=n;i++)
        {
            
             cnt=0;
            for(int  j=1;j<=m;j++)
            {
//                cout<<"task :"<<i<<"  ram: "<<j<<endl;
                int tmp=work(siz[j],i,0,num[i]);
                cost[i][j] =t[i][ tmp ];
//                cout<<cost[i][j]<<endl;
                for(int p=1;p<=n;p++)
                {
                    cnt++;
                    w[i][cnt]=-p*cost[i][j];
//                    cout<<"w[i][cnt]"<<endl;
//                     cout<<w[i][cnt]<<endl;
                }
            }

        }

        KM();

        printf("Case %d\n",++kase);
        printf("Average turnaround time = %.2lf\n",ans*1.0/n );
        for(int i=1;i<=n;i++)
        {
            printf("Program %d runs in region %d from %lld to %lld\n",i,reg[i],tim[ reg[i]][pri[i]+1],tim[reg[i]][ pri[i] ]);

        }
        putchar('\n');
    }


    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值