【题解】[CJOI2019]偷懒

[CJOI2019] 偷懒

题目大意

先审题,意思就是说由于你的妈妈会在你制定的体力和脑力的大框架下帮你制定最优计划,所以请确定一个每天干体力劳动和脑力劳动的计划,使得你做的任务最少。

\(Solution\)

考场上看到Itst五分钟左右写完代码过完编译然后就切掉此题十分震惊然后就开始刚此题了...

考虑建立模型,虽然要求是最坏的方案,但是最坏的方案下仍然是最优问题。

由于一天只能完成一个任务,很自然地拆点,把一天\(day\)分成 \(day_1\)\(day_2\),暂且从\(1->2\)连一条\(w=1\)的边。

考虑什么情况下我们会在这一天做任务,是不是当这一天不管怎么安排既可以做体力劳动,又可以做脑力劳动的时候?

体力劳动和脑力劳动是"且"的关系,那么我们:

\(S->task_{脑力}->day_1-^{w=1}>day_2->task_{体力}->T\)

可以想到最小割。

考虑所有流都会经过\(day_{12}\),所以任何割都可以看做是割掉\(day_1->day_2\)的边。

扫描二维码关注公众号,回复: 5578903 查看本文章

考虑我们为什么要割掉这条边?是因为左右两边可以做的任务都存在了,不存在别的方法可以把左右两边割开了。也就是我们不得不做这一天的任务。

我们要最小化任务,所以就是求最小割啦

考场上不会最小割,也没有想到这一步,但是写了一种手动最小割算法233

上正解吧

#include<bits/stdc++.h>
using namespace std;
inline int qr(){
      register char c=getchar();
      register int ret=0;
      while(c<48||c>57) c=getchar();
      while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
      return ret;
}

#define STO <<
#define Orz <<
#define pb push_back
namespace sol_0{
      const int maxn=2e3+5;
      const int maxe=5e3+5;
      struct E{
        int to,w,nx;
      };
      vector < E > e;
      int head[maxn*3+maxe];
      int cur[maxn*3+maxe];
      int kd[maxn];
      int n,m,k,S,T;
      inline void add(int fr,int to,int w=1,bool f=1){
        e.pb((E){to,w,head[fr]});
        head[fr]=e.size()-1;
        if(f)add(to,fr,0,0);
      }
      int cnt;
      struct ID{
        int wh,bl;
        inline void QAQ(){wh=++cnt;bl=++cnt;}
      }id_da[maxn];
      struct E_data{
        int we,be;
      }arc_e[maxn];
      int id_ta[maxe];
      int d[maxn*3+maxe];
      int Bindr[maxn];
      int Windr[maxn];
      int Tindr[maxn];
      queue < int > q;
      template < class STL > inline void clear(STL&f){STL temp; swap(f,temp);}
      
      inline bool bfs(){
        clear(q);
        for(register int t=1;t<=cnt;++t) cur[t]=head[t],d[t]=0;
        d[S]=1;
        q.push(S);
        while(not q.empty()){
          register int now=q.front();
          q.pop();
          if(now==T) break;
          for(register int t=head[now];t!=-1;t=e[t].nx){
            if((!d[e[t].to])&&e[t].w>0)
                  d[e[t].to]=d[now]+1,q.push(e[t].to);
          }
        }
        return d[T]>0;
      }
      
      inline int dfs(int now,int fl){
        
        if(!fl or now==T) return fl; 
        register int ret=0;
        for(register int t=cur[now];t!=-1;t=e[t].nx){
          cur[now]=t;
          if(d[e[t].to]!=d[now]+1||e[t].w<=0) continue;
          register int en=dfs(e[t].to,min(e[t].w,fl));
          if(en>0){
            e[t].w-=en;   e[t^1].w+=en;
            ret+=en;      fl-=en;
            if(not fl) break;
          }
        }
        return ret;
      }
      
      inline int yyb_captain_algorithm(){
        register int ret=0;
        while(bfs()) ret+=dfs(S,0x3f3f3f3f);
        return ret;
      }
      
      inline int init(const int&a,const int&b,const int& c){
        n=a;m=b;k=c;
        S=++cnt;            T=++cnt;
        memset(head,-1,sizeof head);
        for(register int t=1;t<=n;++t) kd[t]=qr();
        for(register int t=1;t<=n;++t){ id_ta[t]=++cnt; if(kd[t]) add(S,cnt);else add(cnt,T);}
        for(register int t=1;t<=m;++t) id_da[t].QAQ();
        for(register int t=1;t<=m;++t) add(id_da[t].wh,id_da[t].bl);
        for(register int t=1;t<=k;++t){
          register int t1=qr();
          register int t2=qr();
          if(kd[t1]) add(id_ta[t1],id_da[t2].wh);
          else add(id_da[t2].bl,id_ta[t1]);
        }
        cout STO yyb_captain_algorithm() Orz '\n';
        return 0;
      }
}

int main(){
      freopen("in.in","r",stdin);
      freopen("out.out","w",stdout);
      int n=qr(),m=qr(),k=qr();
      return sol_0::init(n,m,k);
}

猜你喜欢

转载自www.cnblogs.com/winlere/p/10554520.html