• 【ContestHunter】【弱省胡策】【Round4】


    01分数规划(网络流)+状压DP+树形DP


    官方题解地址: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 $$

      所以我们得到这样一个定理(重要):$$egin{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
    ",mid,ans);
     97             if (ans<eps) r=mid;
     98             else l=mid;
     99         }
    100         printf("%.2f
    ",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

    B

      更神的状压DP……求包括所有点的,边权和最小的边双?。。。

      $nleq 12 ,mleq 50$,很容易猜到n是指数级……枚举= =而m是多重循环的(由于前面有指数级的枚举,这里大约应该是两重循环吧)

      然而并不会2333

      看题解&标程:

      核心思想是:一个边双可以通过从一个边双(点)开始,不断加链……不断加链得到!

      所以就DP枚举啦~令$f[i]$表示点集$i$为一个边双的最小代价,那么枚举$i$的一个子集,令其为一个边双,然后剩余部分组成一条链,加入到这个边双中。

      预处理出来:

        1.点集S组成一条链,且两端点为x、y的最小边权和

        2.点x连向点集S的最小边权和次小边权(用来将(链/点)连入到边双中

      1 //Round 4 B
      2 #include<vector>
      3 #include<cstdio>
      4 #include<cstring>
      5 #include<cstdlib>
      6 #include<iostream>
      7 #include<algorithm>
      8 #define rep(i,n) for(int i=0;i<n;++i)
      9 #define F(i,j,n) for(int i=j;i<=n;++i)
     10 #define D(i,j,n) for(int i=j;i>=n;--i)
     11 using namespace std;
     12 typedef long long LL;
     13 inline int getint(){
     14     int r=1,v=0; char ch=getchar();
     15     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
     16     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
     17     return r*v;
     18 }
     19 const int N=10100,INF=1<<28;
     20 #define CC(a,b) memset(a,b,sizeof(a))
     21 /*******************template********************/
     22 
     23 
     24 int n,m,bin[N],g[N][15][15],h[N][15][2];
     25 int f[N];
     26 struct edge{int x,y,c,next;}E[N];
     27 int head[15],cnt;
     28 void add(int x,int y,int c){
     29     E[++cnt]=(edge){x,y,c,head[x]}; head[x]=cnt;
     30     E[++cnt]=(edge){y,x,c,head[y]}; head[y]=cnt;
     31 }
     32 
     33 inline void getmin(int &a,int b){a=min(a,b);}
     34 inline int fac(int x){
     35     int ans=1;
     36     for(x=x&(x-1);x;x=x&(x-1)) ans++;
     37     return ans;
     38 }
     39 void init(){
     40     m=(1<<n)-1;
     41     F(i,0,m) F(j,0,n) F(k,0,n) g[i][j][k]=INF;
     42     F(i,1,n){
     43         bin[i]=1<<(i-1);
     44         g[bin[i]][i][i]=0;
     45     }
     46     F(i,1,cnt){
     47         int x=E[i].x,y=E[i].y,s=bin[x]+bin[y];
     48         g[s][x][y]=min(g[s][x][y],E[i].c);//直接相邻的两点
     49     }
     50 
     51     F(i,1,m)
     52         F(x,1,n) F(y,1,n)
     53             if ((bin[x]|i)==i && (bin[y]|i)==i)
     54     for(int j=head[y];j;j=E[j].next)
     55         if ((bin[E[j].y]|i)!=i)
     56             getmin(g[i|bin[E[j].y]][x][E[j].y],g[i][x][y]+E[j].c);
     57     //从链的一端向前扩展
     58 
     59     F(i,0,m) F(j,0,n) F(k,0,1) h[i][j][k]=INF;
     60     F(i,1,m)
     61         F(x,1,n)
     62             if ((bin[x]|i)!=i)//找个在点集i之外的点x
     63     for(int j=head[x];j;j=E[j].next)
     64         if ((bin[E[j].y]|i)==i){
     65             if (E[j].c<=h[i][x][0]){
     66                 h[i][x][1]=h[i][x][0];
     67                 h[i][x][0]=E[j].c;
     68             }else getmin(h[i][x][1],E[j].c);
     69         }//更新从x到i的最短&次短边权
     70 }
     71 void work(){
     72     F(i,1,m) f[i]=INF;
     73     F(i,1,n) f[bin[i]]=0;
     74 
     75     F(i,1,m)
     76         if (fac(i)>=2)//元素个数大于2
     77             for(int s=i&(i-1);s;s=i&(s-1)){
     78                 int t=i-s;
     79                 F(x,1,n) F(y,1,n)
     80                     if ((bin[x]|s)==s && (bin[y]|s)==s){
     81                         if (x==y)
     82                             getmin(f[i],f[t]+g[s][x][x]+h[t][x][0]+h[t][x][1]);
     83                         else 
     84                             getmin(f[i],f[t]+g[s][x][y]+h[t][x][0]+h[t][y][0]);
     85                     }
     86             }
     87     if (f[m]<INF) printf("%d
    ",f[m]);
     88     else puts("Impossible");
     89 }
     90 int main(){
     91 #ifndef ONLINE_JUDGE
     92     freopen("B.in","r",stdin);
     93     freopen("B.out","w",stdout);
     94 #endif 
     95     int T=getint();
     96     while(T--){
     97         n=getint(); m=getint();
     98         cnt=0; CC(head,0);
     99         F(i,1,m){
    100             int x=getint(),y=getint(),c=getint();
    101             add(x,y,c);
    102         }
    103         init(); work();
    104     }
    105     return 0;
    106 }
    View Code

    C

      ……这个……不想说什么了……其实是【TYVJ 五月图论专项有奖比赛】的C题,而且数据规模还更小了……

      然而我个傻逼还是不会做QAQ,直接贴了原来的代码>_>原谅我……

     1 //Round 4 C
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<iostream>
     6 #include<algorithm>
     7 #define rep(i,n) for(int i=0;i<n;++i)
     8 #define F(i,j,n) for(int i=j;i<=n;++i)
     9 #define D(i,j,n) for(int i=j;i>=n;--i)
    10 #define pb push_back
    11 using namespace std;
    12 typedef long long LL;
    13 inline int getint(){
    14     int r=1,v=0; char ch=getchar();
    15     for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
    16     for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
    17     return r*v;
    18 }
    19 const int N=100010;
    20 /*******************template********************/
    21 int to[N<<1],next[N<<1],head[N],cnt;
    22 void add(int x,int y){
    23     to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt;
    24     to[++cnt]=x; next[cnt]=head[y]; head[y]=cnt;
    25 }
    26 
    27 int n,a[N],f[N][2],dep[N],s[N],fa[N],cut;
    28 LL g[N],ans=1e15;
    29 void dfs(int x){
    30     for(int i=head[x];i;i=next[i])
    31         if (to[i]!=fa[x]){
    32             dep[to[i]]=dep[x]+1;
    33             fa[to[i]]=x;
    34             dfs(to[i]);
    35             s[x]+=s[to[i]];
    36             if (s[to[i]]>s[f[x][0]]) f[x][1]=f[x][0],f[x][0]=to[i];
    37             else if (s[to[i]]>s[f[x][1]]) f[x][1]=to[i];
    38             g[x]+=g[to[i]]+s[to[i]];
    39         }
    40 }
    41 LL getans(int x,int cnt){
    42     int t=(f[x][0]==cut || s[f[x][1]]>s[f[x][0]]) ? f[x][1] : f[x][0];
    43     if (2*s[t]>cnt) return 2*s[t]-cnt+getans(t,cnt);
    44     else return 0;
    45 }
    46 void dp(int x){
    47     for(int i=head[x];i;i=next[i])
    48         if (to[i]!=fa[x]){
    49             cut=to[i];
    50             for(int j=x;j;j=fa[j]) s[j]-=s[to[i]];
    51             ans=min(ans,g[1]-g[to[i]]-(LL)s[to[i]]*dep[to[i]]-getans(1,s[1])+g[to[i]]-getans(to[i],s[to[i]]));
    52             for(int j=x;j;j=fa[j]) s[j]+=s[to[i]];
    53             dp(to[i]);
    54         }
    55 }
    56 
    57 int main(){
    58 #ifndef ONLINE_JUDGE
    59     freopen("C.in","r",stdin);
    60     freopen("C.out","w",stdout);
    61 #endif
    62     n=getint();
    63     F(i,2,n){
    64         int x=getint(),y=getint();
    65         add(x,y);
    66     }
    67     F(i,1,n) s[i]=getint();
    68     dfs(1);
    69     dp(1);
    70     printf("%lld
    ",ans);
    71     return 0;
    72 }
    View Code

      

  • 相关阅读:
    6174问题
    阶乘的精确值
    小学生算术
    Primer回顾 数组和指针
    Primer回顾 标准库类型
    绪论
    字符串的存储
    条款39:明智而审慎的使用private继承
    条款34:区分接口继承和实现继承
    条款33:避免遮掩继承而来的名称
  • 原文地址:https://www.cnblogs.com/Tunix/p/4565186.html
Copyright © 2020-2023  润新知