zoukankan      html  css  js  c++  java
  • [hdu6978]New Equipments II

    显然可以费用流来做,具体建图如下——

    点集:源点,汇点,左边$n$​个工人,右边$n$​​​个设备

    边集:源点向第$i$​个工人连$(1,a_{i})$​的边,第$i$​个设备向汇点连$(1,b_{i})$​​​的边,工人向可用的设备连$(1,0)$​的边

    跑最小费用最大流,流量为$i$时的费用即为$i$时的答案

    但注意到要跑$n$次spfa,每一次的最坏复杂度为$o(n^{3})$,显然无法通过

    实际上,spfa即找到$x$和$y$,使得第$x$个工人和第$y$个设备都未被使用过,且第$x$个工人能流到第$y$个设备,在此基础上最大化$a_{x}+b_{y}$​,那么不妨手动来实现此功能

    考虑按照$a_{i}$​​从大到小枚举左边未被使用过的的工人,并递归其能流到的点,求出其中设备$b_{i}$​的最大值

    注意到当一个点已经被访问过,显然再访问一定不优于之前,单次复杂度即降为$o(n^{2})$​

    每一个点只会被访问一次,因此复杂度瓶颈在于遍历边集,使用bfs来代替dfs,并对点分类讨论:

    1.对于工人,其几乎到所有设备都有边,缺的仅有$o(m)$条限制和$o(n)$条之前流过的边,因此只需要遍历所有当前未被访问的点,并搜索其中可以访问的点

    注意到一个未访问的点被遍历,要么被访问,要么属于$o(n+m)$​​条边之一,因此总复杂度即$o(m)$​​​

    2.对于设备,其出边只有$o(n)$条之前流过的边的反向边,暴力遍历边集即可,总复杂度即$o(n)$

    由此,单次复杂度降为$o(m)$​​,总复杂度即$o(nm)$​​,可以通过

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 4005
      4 #define ll long long
      5 queue<int>q;
      6 vector<int>v[N];
      7 int t,n,m,x,y,a[N],b[N],id[N],visa[N],visb[N],vis[N],nex[N],pre[N<<1],mx[N],e[N][N];
      8 ll ans;
      9 bool cmp(int x,int y){
     10     return a[x]>a[y];
     11 }
     12 int bfs(int k){
     13     int s=0;
     14     q.push(k);
     15     vis[k]=1;
     16     while (!q.empty()){
     17         int k=q.front();
     18         q.pop();
     19         if (k<=n){
     20             for(int i=nex[0],j=0;i<=n;j=i,i=nex[i])
     21                 if (e[k][i]){
     22                     pre[i+n]=k;
     23                     q.push(i+n);
     24                     nex[j]=nex[i],i=j;
     25                 }
     26         }
     27         else{
     28             k-=n;
     29             if ((!visb[k])&&(b[s]<b[k]))s=k;
     30             for(int i=0;i<v[k].size();i++)
     31                 if (!vis[v[k][i]]){
     32                     pre[v[k][i]]=k+n;
     33                     q.push(v[k][i]);
     34                     vis[v[k][i]]=1;
     35                 }
     36         }
     37     }
     38     return s;
     39 }
     40 int calc(){
     41     int ans=0;
     42     for(int i=1;i<=n;i++)vis[i]=0;
     43     for(int i=0;i<=n;i++)nex[i]=i+1;
     44     for(int i=1;i<=(n<<1);i++)pre[i]=0;
     45     for(int i=1;i<=n;i++){
     46         mx[i]=0;
     47         if ((!visa[id[i]])&&(!vis[id[i]])){
     48             mx[i]=bfs(id[i]);
     49             if (mx[i])ans=max(ans,a[id[i]]+b[mx[i]]);
     50         }
     51     }
     52     if (!ans)return 0;
     53     for(int i=1;i<=n;i++)
     54         if ((mx[i])&&(a[id[i]]+b[mx[i]]==ans)){
     55             visa[id[i]]=1,visb[mx[i]]=1;
     56             for(int lst=mx[i]+n,j=pre[lst];j;lst=j,j=pre[j]){
     57                 if (j<=n){
     58                     e[j][lst-n]=0;
     59                     v[lst-n].push_back(j);
     60                 }
     61                 else{
     62                     e[lst][j-n]=1;
     63                     for(int k=0;k<v[j-n].size();k++)
     64                         if (v[j-n][k]==lst){
     65                             v[j-n].erase(v[j-n].begin()+k);
     66                             break;
     67                         }
     68                 }
     69             }
     70             break;
     71         }
     72     return ans;
     73 }
     74 int main(){
     75     scanf("%d",&t);
     76     while (t--){
     77         scanf("%d%d",&n,&m);
     78         ans=0;
     79         for(int i=1;i<=n;i++){
     80             visa[i]=visb[i]=0; 
     81             v[i].clear();
     82         }
     83         for(int i=1;i<=n;i++)
     84             for(int j=1;j<=n;j++)e[i][j]=1;
     85         for(int i=1;i<=n;i++){
     86             scanf("%d",&a[i]);
     87             id[i]=i;
     88         }
     89         sort(id+1,id+n+1,cmp);
     90         for(int i=1;i<=n;i++)scanf("%d",&b[i]);
     91         for(int i=1;i<=m;i++){
     92             scanf("%d%d",&x,&y);
     93             e[x][y]=0;
     94         }
     95         for(int i=1;i<=n;i++){
     96             int s=calc();
     97             if (!s){
     98                 for(;i<=n;i++)printf("-1
    ");
     99                 break;
    100             }
    101             ans+=s;
    102             printf("%lld
    ",ans);
    103         }
    104     }
    105     return 0;
    106 }
    View Code
  • 相关阅读:
    Apache 虚拟主机 VirtualHost 配置
    EAX、ECX、EDX、EBX寄存器的作用
    Python中文文档 目录(转载)
    八度
    POJ 3268 Silver Cow Party (最短路)
    POJ 2253 Frogger (求每条路径中最大值的最小值,Dijkstra变形)
    2013金山西山居创意游戏程序挑战赛——复赛(1) HDU 4557 非诚勿扰 HDU 4558 剑侠情缘 HDU 4559 涂色游戏 HDU 4560 我是歌手
    HDU 4549 M斐波那契数列(矩阵快速幂+欧拉定理)
    UVA 11624 Fire! (简单图论基础)
    HDU 3534 Tree (树形DP)
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15087918.html
Copyright © 2011-2022 走看看