官方题解地址:http://pan.baidu.com/s/1mg5S5z6

A

  好神啊= =第一次写01分数规划

  其实分数规划是要求$$ Maximize/Minimize \ \ L=\frac{A(x)}{B(x)}$$

  这里我们拿最大来举例吧……因为本题就是最大嘛~

  通用解法是:二分= =

  假设最优解为$\lambda^*$,那么有$$\lambda^*=f(x^*)=\frac{A(x^*)}{B(x^*)} \\ \Rightarrow \lambda^* *B(x^*)=A(x^*) \\ \Rightarrow 0=A(x^*)-\lambda^* *B(x^*) $$

  那么我们由上面的形式构造一个新函数$g(\lambda)$:$$g(\lambda)=max_{x \in S} \{A(x)-\lambda*B(x)\}$$

  这个函数是有单调性的……我就不证明了……重点是后面的部分:

$$ \lambda<\lambda^* \Rightarrow \lambda<\frac{A(x^*)}{B(x^*)} \Rightarrow A(x^*)-\lambda *B(x^*) >0 \\ \lambda>\lambda^* \Rightarrow \lambda>\frac{A(x^*)}{B(x^*)} \Rightarrow A(x^*)-\lambda *B(x^*) <0 $$

  所以我们得到这样一个定理(重要):$$\begin{cases} g( \lambda )=0 & \Leftrightarrow & \lambda = \lambda^* \\ g( \lambda )<0 & \Leftrightarrow & \lambda < \lambda^* \\ g( \lambda )>0 & \Leftrightarrow & \lambda > \lambda^* \end{cases} $$

  这题里面,$A(x)$就是边权和,$\lambda*B(x)$就是选这些点的代价啦。

  那么很明显对于一个已知的$\lambda$(收益比),我们可以用最大权闭合图的模型来求出$g(\lambda)$,(因为是最大!)从而得知我们二分的这个答案$\lambda$是偏大还是偏小了……

  这玩意是不是叫点边均带权的最大密度子图啊QAQ

 

  然而这题有个细节要注意,因为我们用的是最大权闭合图,这里的边权又比较特殊……所以不会出现$g(\lambda)<0$的情况,(那种时候会变成=0),所以我们应该是在>0的时候令L=mid;else R=mid;

  而我一开始是反过来写的……所以就跪了TAT 后来我灵(nao)机(zi)一(yi)动(chou),将ans<0改成了ans<eps……这就将<=0的情况都包括进去了→_→顺利出解。

  

  事实上考试时我这题只有暴力分= =因为我数组开!小!了!……一开始定数组大小的时候没想出来正解……所以是直接按点数和边数开的……但是如果是网络流的话,点数应该是$n+m$,边数会是$n+3m$……(没算源汇)QAQTAT

  1 //Round4 A
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<queue>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<iostream>
  8 #include<algorithm>
  9 #define rep(i,n) for(int i=0;i<n;++i)
 10 #define F(i,j,n) for(int i=j;i<=n;++i)
 11 #define D(i,j,n) for(int i=j;i>=n;--i)
 12 #define pb push_back
 13 using namespace std;
 14 typedef long long LL;
 15 inline int getint(){
 16     int r=1,v=0; char ch=getchar();
 17     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
 18     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
 19     return r*v;
 20 }
 21 const int N=10010,M=40010;
 22 const double eps=1e-6,INF=1e10;
 23 /*******************template********************/
 24 
 25 int n,m,u[M],v[M];
 26 double p[M],ans,c[N];
 27 struct edge{int to;double v;};
 28 struct Net{
 29     edge E[M];
 30     int head[N],nxt[M<<1],cnt;
 31     void ins(int x,int y,double v){
 32         E[++cnt]=(edge){y,v}; nxt[cnt]=head[x]; head[x]=cnt;
 33     }
 34     void add(int x,int y,double v){
 35         ins(x,y,v); ins(y,x,0);
 36     }
 37     int S,T,cur[N],d[N];
 38     queue<int>Q;
 39     bool mklevel(){
 40         memset(d,-1,sizeof d);
 41         d[S]=0;
 42         Q.push(S);
 43         while(!Q.empty()){
 44             int x=Q.front(); Q.pop();
 45             for(int i=head[x];i;i=nxt[i])
 46                 if (d[E[i].to]==-1 && E[i].v>0){
 47                     d[E[i].to]=d[x]+1;
 48                     Q.push(E[i].to);
 49                 }
 50         }
 51         return d[T]!=-1;
 52     }
 53     double dfs(int x,double a){
 54         if (x==T) return a;
 55         double flow=0.0;
 56         for(int &i=cur[x];i && a-flow>eps;i=nxt[i]){
 57             if (d[E[i].to]==d[x]+1 && E[i].v>eps){
 58                 double f=dfs(E[i].to,min(a-flow,E[i].v));
 59                 E[i].v-=f;
 60                 E[i^1].v+=f;
 61                 flow+=f;
 62             }
 63         }
 64         if (fabs(flow)<eps) d[x]=-1;
 65         return flow;
 66     }
 67     void Dinic(){
 68         while(mklevel()){
 69             F(i,0,T) cur[i]=head[i];
 70             ans-=dfs(S,INF);
 71         }
 72     }
 73     void build(double x){
 74 //        cout <<"mid="<<x<<endl;
 75         cnt=1; memset(head,0,sizeof head);
 76         S=0,T=n+m+1; ans=0.0;
 77         F(i,1,n) add(S,i,(double)c[i]*x);
 78         F(i,1,m){
 79             ans+=p[i];
 80             add(u[i],i+n,INF);
 81             add(v[i],i+n,INF);
 82             add(i+n,T,p[i]);
 83         }
 84     }
 85     void init(){
 86         n=getint(); m=getint();
 87         F(i,1,n) c[i]=getint();
 88         F(i,1,m){
 89             u[i]=getint(); v[i]=getint(); p[i]=getint();
 90         }
 91         double l=0,r=1e9,mid;
 92         while(r-l>eps){
 93             mid=(l+r)/2;
 94             build(mid);
 95             Dinic();
 96 //            printf("mid=%f ans=%f\n",mid,ans);
 97             if (ans<eps) r=mid;
 98             else l=mid;
 99         }
100         printf("%.2f\n",l);
101     }
102 }G1;
103 
104 int main(){
105 #ifndef ONLINE_JUDGE
106     freopen("A.in","r",stdin);
107     freopen("A.out","w",stdout);
108 #endif
109     G1.init();
110     return 0;
111 }
View Code

相关文章: