zoukankan      html  css  js  c++  java
  • 2018.07.13【省赛模拟】模拟B组 【GDOI2016模拟】作业分配

    #Description
    暑假里,总有某些同学由于贪玩而忘记做作业。这些人往往要等到暑假快结束时才想起堆积如山的作业,但在这最后几天的时间里把这些作业做完已经不太现实了,于是“志同道合”的他们想出了一个妙招。
    假设现在有n科作业,他们把第i科作业按作业量平均分成ai份,他们总共有m个人,第j个人只愿意做其中任意的bj份作业,而且我们知道ai的和等于bj的和,以及把第i科作业的其中一份给第j个人做的时间是ci,j。现在他们想分配下各自的任务,一起把作业做完,然后再%#&%&#%%&^
    现在的问题来了,他们希望所有人做作业的总时间的和最小,你能帮助他们解决问题吗?

    #Input
    输入文件的第一行有两个n,m表示有多少科作业和多少个人,第二行有n个数依次表示ai,第三行有m个数依次表示bj,最后n行,每行m个数表示ci,j。

    #Output
    输出文件包含一行为最少的时间总和。

    #Sample Input
    2 2
    3 5
    5 3
    1 2
    2 1

    #Sample Output
    10
    【样例解释】
    第1个人做完所有的第1科作业以及第2科作业的其中2份,第2个人把第2科另外3份做完。

    #Data Constraint
    第一个点 n<=5 m<=5 ai,bi<=15 sum(ai)<=20
    第二个点 n<=10 m<=10 ai,bi<=20 sum(ai)<=100
    第三个点 n<=30 m<=30 ai,bi<=600 sum(ai)<=10000
    第四个点到第十个点 n<=200 m<=200 ai,bi<=10000 sum(ai)<=1000000

    #题解
    题意:很好懂。
    然后第一眼(很关键):最小费用最大流。
    很暴力,但是看到数据感觉很正确。
    恩,然后就暴力码3小时。0分。
    为什么呢?因为我打错了一些东东,小数据竟然没有拍出来!
    然后TLE40。
    为什么呢?因为最小费用最大流的时间复杂度很玄学,而且时间限制为500ms。管他是什么zkw或是最普通的spfa,我出题人绝对卡掉。

    100%
    题解直接否决了最小费用最大流。然后就讲到拆点做一边二分图匹配。
    然而点数很大,然后就用一种我不懂的方法来拆点,然后做KM(带权二分图匹配)。
    然后题解我丢在这里大家慢慢看。
    这里写图片描述

    那我怎么做的呢?
    真·100%
    其实有另一种方法是可以用费用流来做的。垃圾出题人
    我们建图就:
    1)源点连流量为y[i],费用为0的点到每个人
    2)中间每个人连流量为INF,费用为w[i,j]的到每个作业。
    3)每个作业连流量为x[i],费用为0的点到汇点。
    然后呢,这样直接做是会爆的。
    那么我们就考虑考虑优化。
    我们发现,对于zkw或是别的费用流,都是根据一个最短路(费用为路的长度),然后来更新流量。
    这个跟EK的算法很相似,自己学,我不讲,难不成你咬我?
    这里写图片描述
    然后呢,我们发现,每次更新,我们只会流最短的路,于是我们就可以动态地来加入一些点,不用每次都循环这么多次。
    至于如何弄,我们来看一张图:
    这里写图片描述
    这张图上,我们流完了第一次,要加入灰色的边。那么我们由于加入了最小的边,然后最小的边连到的点的flew=0,那么我们就找到次小,加入。由于次小的边连到的点的flew也为0,那么我们继续找。找到一条边——最大,它的连到的点的flew>0于是乎,我们就可以停止当前点的加边。
    这样子我们在每次更新流量时,不会跑过多的边导致时间保证不了。
    神奇的优化。
    然后如果你打得丑像我一样,你可能需要用到一些O3常数上的优化。
    我P党真的无语,这个方法跑600、700ms,别的C党就100ms200ms。

    但是事后我转成C了之后一样是卡过去的,而且代码量惊人。

    #include<bits/stdc++.h>
    using namespace std;
    bool b[100002],pd[100002];
    int i,j,k,l,n,m,t,tot,tot1,js,w[301][301],mapp[301][301],op[301][301],x[100001],y[100001];
    long long ans,maxx,last[100001],next[100001],tov[100001],last1[100001],flew1[100001],next1[100001],tov1[100001],flew[100001],value[100001],value1[100001],id1[100001],id[100001],bh[100001],kp[100001],dis[100001],d[100001],now[100001],need[100001];
    __attribute__((optimize("O3")))
    void ort(int l,int r,int p)
    {
    	int i=l,j=r,k,m;
     	m=mapp[l+(r-l)/3][p];
     	do
     	{
      	  while(mapp[i][p]<m)i++;
          while(mapp[j][p]>m)j--;
          if(i<=j)swap(mapp[i][p],mapp[j][p]),swap(op[i][p],op[j][p]),i++,j--;
      	 }while(i<=j);
         if(l<j)ort(l,j,p);
         if(r>i)ort(i,r,p);
    }
    __attribute__((optimize("O3")))
    void insert2(int x,int y){tot1++,tov1[tot1]=y,next1[tot1]=kp[x],kp[x]=tot1;}
    __attribute__((optimize("O3")))
    void insert1(int x,int y){tot1++,tov1[tot1]=y,next1[tot1]=last1[x],last1[x]=tot1;}
    __attribute__((optimize("O3")))
    void insert(int x,int y){tot++,tov[tot]=y,next[tot]=last[x],last[x]=tot;}
    __attribute__((optimize("O3")))
    long long min(int x,long long y){if(x<y)return x;return y;}
    __attribute__((optimize("O3")))
    int flow(int x,int t)
    {
    	 int k,l;
    	 long long minn;
      	 pd[x]=true;
         if(x==n+m+2){ans+=t*dis[1];return t;}
         k=last1[x];
         while(k!=0)
         {
      			if((flew1[k]>0)and (pd[tov1[k]]==false) and (dis[x]==dis[tov1[k]]+value1[k]))
      			{
    			     minn=min(t,flew1[k]);
              		 l=flow(tov1[k],minn);
                 	 if(l>0)
                 	 {
                     	  flew1[id1[k]]+=l;
                          flew1[k]-=l;
                          last1[x]=k;
                          return l;
                      }
              	}
                 k=next1[k];
         }
            last1[x]=0;
            return 0;
    }
    __attribute__((optimize("O3")))
    bool change()
    {
    	 int minn=2147483647,k;
      	 for(i=1;i<=n+m+2;i++)
      	 {
         	  if(pd[i])
         	  {
              	   k=kp[i];
                   while(k!=0)
                   {
                   		if((flew1[k]>0)and(pd[tov1[k]]==false)and(dis[tov1[k]]+value1[k]-dis[i]<minn))
                     	 minn=dis[tov1[k]]+value1[k]-dis[i];
                      	k=next1[k];
                      }
    		  }
        }
              if(minn==2147483647)return true;
              for(i=1;i<=n+m+2;i++)
                    if(pd[i])dis[i]+=minn,pd[i]=false;
    		  return false;
    	}
    __attribute__((optimize("O3")))
    void up(int x){while((x/2>0)and(dis[d[x]]<dis[d[x/2]]))bh[d[x]]=x/2,bh[d[x/2]]=x,swap(d[x],d[x/2]),x/=2;}
    __attribute__((optimize("O3")))
    void down(int y)
    {
    	 int x=1;
      	 while(((x*2<=t)and (dis[d[x]]>dis[d[x*2]])) or ((x*2+1<=t) and (dis[d[x]]>dis[d[x*2+1]])))
      	 {
                    if ((x*2+1<=t) and (dis[d[x*2+1]]<dis[d[x*2]]))
                            bh[d[x]]=x*2+1,bh[d[x*2+1]]=x,swap(d[x],d[x*2+1]),x=x*2+1;
                    else
                            bh[d[x]]=x*2,bh[d[x*2]]=x,swap(d[x],d[x*2]),x*=2;
                        }
    }
    __attribute__((optimize("O3")))
    inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; }
    __attribute__((optimize("O3")))
    void read(int &data){data=0;char ch=0; while(ch<'0'||ch>'9')ch=nc(); while(ch>='0'&&ch<='9')data=data*10+ch-'0',ch=nc();}
    __attribute__((optimize("O3")))
    int main()
    {
     	read(n),read(m);
    	for(i=1;i<=n;i++)read(y[i]);
    	for(i=1;i<=m;i++)read(x[i]);
    	for(i=1;i<=n;i++)for(j=1;j<=m;j++)read(w[i][j]),mapp[i][j]=w[i][j];
    	for(i=1;i<=m;i++)for(j=1;j<=n;j++)op[j][i]=j+m+1;
    	for(i=1;i<=m;i++)insert(1,1+i),flew[tot]=x[i],insert(1+i,1),flew[tot]=x[i];
    	for(i=1;i<=n;i++)for(j=1;j<=m;j++)insert(j+1,i+m+1),value[tot]=w[i][j],flew[tot]=2147483647,insert(i+m+1,j+1),flew[tot]=2147483647,value[tot]=w[i][j];
    	for(i=1;i<=n;i++)insert(1+m+i,2+n+m),flew[tot]=y[i],insert(2+n+m,1+m+i),flew[tot]=y[i];
    	for(i=0;i<=100000;i++)dis[i]=2147483647;
     	maxx=dis[1],t=1,dis[n+m+2]=0,b[n+m+2]=true,bh[n+m+2]=t,d[t]=n+m+2;
        up(t);
        while (t>0)
        {
    	 	  b[d[1]]=true,i=last[d[1]];
         	  while(i>0)
         	  {
       			  if((b[tov[i]]==false)and(dis[d[1]]+value[i]<dis[tov[i]]))
       			  {
    					if(dis[tov[i]]==maxx)
    						t++,dis[tov[i]]=dis[d[1]]+value[i],bh[tov[i]]=t,d[t]=tov[i],up(t);
    					else
    			 		dis[tov[i]]=dis[d[1]]+value[i],up(bh[tov[i]]);
    				}
    
    				i=next[i];
    			}
       			bh[d[1]]=0,bh[d[t]]=1,d[1]=d[t],t--,down(t);
    	}
    	for(i=1;i<=m;i++)insert1(1,1+i),value1[tot1]=0,id1[tot1]=tot1+1,flew1[tot1]=x[i],insert1(1+i,1),id1[tot1]=tot1-1,flew1[tot1]=0,value1[tot1]=0;
    	for(i=1;i<=n;i++)insert1(1+m+i,2+n+m),need[i+m+1]=tot1,value1[tot1]=0,id1[tot1]=tot1+1,flew1[tot1]=y[i],insert1(2+n+m,1+m+i),id1[tot1]=tot1-1,flew1[tot1]=0,value1[tot1]=0;
    	for(i=1;i<=m;i++)now[i]=1;
    	for(i=1;i<=m;i++)ort(1,n,i),insert1(i+1,op[now[i]][i]),value1[tot1]=mapp[1][i],id1[tot1]=tot1+1,flew1[tot1]=2147483647,insert1(op[now[i]][i],i+1),value1[tot1]=-mapp[1][i],id1[tot1]=tot1-1,flew1[tot1]=0;
    	for(i=0;i<=100000;i++)kp[i]=last1[i];
    	do
    	{
    		for(i=1;i<=n+m+2;i++)last1[i]=kp[i];
    		while(flow(1,2147483647)>0)
    			for(i=1;i<=n+m+2;i++)pd[i]=false;
    		for(i=1;i<=m;i++)
    		{
    			if(now[i]==n)continue;
    			j=kp[i+1];
    			while(j>0)
    			{
    				if(tov1[j]!=1)
    				{
    					k=need[tov1[j]];
    					if(flew1[k]==0)
    					{
    						now[i]++;
    						if(now[i]>n)break;
    						insert2(i+1,op[now[i]][i]);
          					value1[tot1]=mapp[now[i]][i];
               				id1[tot1]=tot1+1;
                   			flew1[tot1]=2147483647;
                      		insert2(op[now[i]][i],i+1);
                        	value1[tot1]=-mapp[now[i]][i];
                         	id1[tot1]=tot1-1;
                          	flew1[tot1]=0;
    					}
    				}
    				j=next1[j];
    			}
    		}
    	}while(!change());
    	printf("%lld",ans);
    }
    
    我活在这夜里。无论周围多么黑暗,我都要努力发光!我相信着,终有一天,我会在这深邃的夜里,造就一道最美的彩虹。
  • 相关阅读:
    173. Binary Search Tree Iterator
    199. Binary Tree Right Side View
    230. Kth Smallest Element in a BST
    236. Lowest Common Ancestor of a Binary Tree
    337. House Robber III
    449. Serialize and Deserialize BST
    508. Most Frequent Subtree Sum
    513. Find Bottom Left Tree Value
    129. Sum Root to Leaf Numbers
    652. Find Duplicate Subtrees
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11148407.html
Copyright © 2011-2022 走看看