zoukankan      html  css  js  c++  java
  • BZOJ1061

    Portal

    Description

    实行一个(n(nleq10^3))天的项目,其中第(i)天至少需要(b_i)个人。一共有(m(mleq10^4))类志愿者可以招募,其中第(i)类可以从第(s_i)天工作到第(t_i)天,招募费用是每人(c_i)元。求最小花费的招募方案。

    Solution1

    根据题意,很容易列出一个线性规划:

    [egin{align} min quad & sum_{i=1}^m c_ix_i \ s.t. quad & sum_{i=1}^m a_{ji}x_i geq b_j \ & x_igeq0 end{align} $$其中$x_i$代表第$i$类志愿者的个数,$a_{ji}=1$当且仅当$s_ileq j leq t_i$。 该线性规划可转化为其对偶问题: ]

    egin{align}
    max quad & sum_{j=1}^n b_jy_j
    s.t. quad & sum_{j=1}^n a_{ji}y_j leq c_i
    & y_jgeq0
    end{align}

    [用单纯形求解即可。 ##Solution2 还可以用费用流求解。按如下方式建图: - $s=0,t=n+1$,共$n+2$个点; - 连边$(s,1)$,容量为足够大的数$U$,费用为$0$; - 连边$(i,i+1)$,容量为$U-b_i$,费用为$0$; - 对于第$i$类志愿者,连边$(s_i,t_i+1)$,容量为$+infty$,费用为$c_i$。 第$i$类志愿者代表的边每有$1$的流量,原图$s_i$到$t_i$就可以少$1$的流量,就相当于招募了一个志愿者。 ##Code ```cpp //[Noi2008]志愿者招募 #include <cstdio> inline char gc() { static char now[1<<16],*S,*T; if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;} return *S++; } inline int read() { int x=0; char ch=gc(); while(ch<'0'||'9'<ch) ch=gc(); while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc(); return x; } int const N=1e3+10; double const EPS=1e-8; bool equal0(double x) {return -EPS<x&&x<EPS;} int n,m; double a[N*10][N]; void pivot(int x,int y) { double t=a[x][y]; a[x][y]=1; for(int i=0;i<=n;i++) a[x][i]/=t; for(int i=0;i<=m;i++) { if(i==x||equal0(a[i][y])) continue; t=a[i][y]; a[i][y]=0; for(int j=0;j<=n;j++) a[i][j]-=a[x][j]*t; } } void simplex() { while(true) { int x=0,y=0; double minX=1e18; for(int i=1;!y&&i<=n;i++) if(a[0][i]>EPS) y=i; if(!y) return; for(int i=1;i<=m;i++) if(a[i][y]>EPS&&a[i][0]/a[i][y]<minX) minX=a[i][0]/a[i][y],x=i; if(!x) return; pivot(x,y); } } int main() { n=read(),m=read(); for(int i=1;i<=n;++i) a[0][i]=read(); for(int i=1;i<=m;++i) { int x=read(),y=read(); for(int j=x;j<=y;++j) a[i][j]=1; a[i][0]=read(); } simplex(); printf("%lld ",-(long long)a[0][0]); return 0; } ``` ```cpp //[Noi2008]志愿者招募 #include <cstdio> #include <algorithm> #include <queue> using namespace std; typedef long long lint; inline char gc() { static char now[1<<16],*S,*T; if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;} return *S++; } inline int read() { int x=0; char ch=gc(); while(ch<'0'||'9'<ch) ch=gc(); while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc(); return x; } int const N=1e3+10; int const INF=0x7FFFFFFF; int n,m; int s,t; int h[N],cnt; struct edge{int v,c,w,nxt;} ed[N*30]; void edAdd(int u,int v,int c,int w) { cnt++; ed[cnt].v=v,ed[cnt].c=c,ed[cnt].w=w,ed[cnt].nxt=h[u],h[u]=cnt; cnt++; ed[cnt].v=u,ed[cnt].c=0,ed[cnt].w=-w,ed[cnt].nxt=h[v],h[v]=cnt; } int pre[N],dst[N]; queue<int> Q; bool inQ[N]; bool SPFA() { for(int i=s;i<=t;i++) dst[i]=INF,pre[i]=0; dst[s]=0; Q.push(s),inQ[s]=true; while(!Q.empty()) { int u=Q.front(); Q.pop(),inQ[u]=false; for(int i=h[u];i;i=ed[i].nxt) { int v=ed[i].v,w=ed[i].w; if(ed[i].c&&dst[u]+w<dst[v]) { dst[v]=dst[u]+w,pre[v]=i; if(!inQ[v]) Q.push(v),inQ[v]=true; } } } return dst[t]<INF; } lint netFlow() { lint cost=0; while(SPFA()) { int fl=INF; for(int i=pre[t];i;i=pre[ed[i^1].v]) fl=min(fl,ed[i].c); for(int i=pre[t];i;i=pre[ed[i^1].v]) ed[i].c-=fl,ed[i^1].c+=fl; cost+=(lint)fl*dst[t]; } return cost; } int main() { n=read(),m=read(); s=0,t=n+1; cnt=1; edAdd(s,1,INF,0); for(int i=1;i<=n;i++) edAdd(i,i+1,INF-read(),0); for(int i=1;i<=n;i++) { int s=read(),t=read(),w=read(); edAdd(s,t+1,INF,w); } printf("%lld ",netFlow()); return 0; } ``` ##P.S. 感觉对偶问题不大好理解呀...]

  • 相关阅读:
    Android studio开发找不到HttpClient问题
    Android studio开发找不到HttpClient问题
    互联网应用之传递HTTP参数
    互联网应用之传递HTTP参数
    计算机组成原理
    计算机组成原理
    【NYOJ】[40]公约数和公倍数
    【NYOJ】[40]公约数和公倍数
    【NYOJ】[39]水仙花数
    【NYOJ】[39]水仙花数
  • 原文地址:https://www.cnblogs.com/VisJiao/p/BZOJ1061.html
Copyright © 2011-2022 走看看