zoukankan      html  css  js  c++  java
  • BZOJ 1565 NOI2009 植物大战僵尸 topo+最小割(最大权闭合子图)

    题目链接:https://www.luogu.org/problemnew/show/P2805(bzoj那个实在是有点小小的辣眼睛。。。我就把洛谷的丢出来吧。。。)

    题意概述:给出一张有向图,这张有向图上的每个点都有一个点权,想要访问某个点必须要先访问这个点所能够访问(遍历)到的所有点,在访问到一个点之后将会得到这个点的权值(可正可负)。问访问这张图可以得到的最大点权和。

    原题说过来说过去实际上是描述了一个植物之间的保护关系,也就是说明了植物之间的先后访问顺序之间的关系。可以描述为要“要访问点a,先要访问点b”这样的形式,并且题意总结出来之后很容易发现这就是一个最大权闭合子图问题。

    但是我们注意到原题给出的并不一定是一个DAG图。事实上,可能有些植物互相保护,导致僵尸只能当炮灰。。。。于是我们需要把环去掉,这一步可以topo序解决,只是不是真的topo,而是从入度为0的点开始的(访问所有可以不经过环就可以访问到的点)。

    然后就是直接网络流上跑最大权闭合子图。但是值得注意的是最大权闭合子图是满足一种推导关系,即上面的“要访问点a,先要访问先b”这种关系形成的一条有向边,容量为inf,因为要满足这样的推导关系,所以上面求topo的时候连的边要反过来。然后原点向所有点权为正的边连一条边,容量为点权;所有点权为负的点向汇点连一条边,容量为点权的相反数。在求最小割的时候如果一条边被割掉,那么意义就是做出选择(S有关的边是不选这个点,T有关的边是选了这个点)之后付出的代价。

    最后只需要把所有的正权点权值相加(可以得到的最大收益),减去最小割(付出的最小代价),就是我们最终获得的最大收益。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<algorithm>
      6 #include<cmath>
      7 #include<queue>
      8 #include<set>
      9 #include<map>
     10 #include<vector>
     11 #include<cctype>
     12 using namespace std;
     13 const int MAXN=25;
     14 const int MAXM=35;
     15 
     16 int N,M,sco[MAXN][MAXM];
     17 struct XY{ int x,y; };
     18 vector<XY>att[MAXN][MAXM];
     19 struct graph{
     20     static const int maxn=605;
     21     static const int maxm=360050;
     22     struct edge{ int from,to,next; }E[maxm];
     23     int n,first[maxn],np,rd[maxn],topo[maxn];
     24     graph(){ np=0; }
     25     void add_edge(int u,int v){
     26         E[++np]=(edge){u,v,first[u]};
     27         first[u]=np;
     28     }
     29     void topo_sort(){
     30         queue<int>q;
     31         for(int i=1;i<=n;i++)
     32             if(!rd[i]) topo[i]=1,q.push(i);
     33         while(!q.empty()){
     34             int i=q.front(); q.pop();
     35             for(int p=first[i];p;p=E[p].next){
     36                 int j=E[p].to;
     37                 if(--rd[j]==0) topo[j]=1,q.push(j);
     38             }
     39         }
     40     }
     41 }gp;
     42 struct NET{
     43     static const int maxn=605;
     44     static const int maxm=360050;
     45     static const int inf=1e7+5;
     46     struct edge{ int from,to,next,cap,flow; }E[maxm<<1];
     47     int S,T,n,first[maxn],np,fl[maxn],gap[maxn],d[maxn],cur[maxn];
     48     NET(){ np=0; }
     49     void add_edge(int u,int v,int w){
     50         E[++np]=(edge){u,v,first[u],w,0};
     51         first[u]=np;
     52         E[++np]=(edge){v,u,first[v],0,0};
     53         first[v]=np;
     54     }
     55     void BFS(){
     56         queue<int>q;
     57         for(int i=1;i<=n;i++) d[i]=n;
     58         d[T]=0; q.push(T);
     59         while(!q.empty()){
     60             int i=q.front(); q.pop();
     61             for(int p=first[i];p;p=E[p].next){
     62                 int j=E[p].to,pp=(p-1^1)+1;
     63                 if(E[pp].cap>E[pp].flow&&d[j]==n) d[j]=d[i]+1,q.push(j);
     64             }
     65         }
     66     }
     67     int augment(){
     68         int now=T,flow=inf;
     69         while(now!=S){
     70             flow=min(flow,E[fl[now]].cap-E[fl[now]].flow);
     71             now=E[fl[now]].from;
     72         }
     73         now=T;
     74         while(now!=S){
     75             E[fl[now]].flow+=flow,E[(fl[now]-1^1)+1].flow-=flow;
     76             now=E[fl[now]].from;
     77         }
     78         return flow;
     79     }
     80     int ISAP(){
     81         memcpy(cur,first,sizeof(first));
     82         BFS();
     83         for(int i=1;i<=n;i++) gap[d[i]]++;
     84         int now=S,flow=0;
     85         while(d[S]<n){
     86             if(now==T) flow+=augment(),now=S;
     87             bool ok=0;
     88             for(int p=cur[now];p;p=E[p].next){
     89                 int j=E[p].to;
     90                 if(E[p].cap>E[p].flow&&d[j]+1==d[now]){
     91                     ok=1,fl[j]=cur[now]=p,now=j;
     92                     break;
     93                 }
     94             }
     95             if(!ok){
     96                 int minl=n;
     97                 for(int p=first[now];p;p=E[p].next){
     98                     int j=E[p].to;
     99                     if(E[p].cap>E[p].flow&&d[j]+1<minl) minl=d[j]+1;
    100                 }
    101                 if(--gap[d[now]]==0) break;
    102                 gap[d[now]=minl]++;
    103                 cur[now]=first[now];
    104                 if(now!=S) now=E[fl[now]].from;
    105             }
    106         }
    107         return flow;
    108     }
    109 }net;
    110 
    111 void data_in()
    112 {
    113     scanf("%d%d",&N,&M);
    114     int w,x,y;
    115     for(int i=1;i<=N;i++)
    116     for(int j=1;j<=M;j++){
    117         scanf("%d%d",&sco[i][j],&w);
    118         for(int k=1;k<=w;k++){
    119             scanf("%d%d",&x,&y);
    120             att[i][j].push_back((XY){x+1,y+1});
    121         }
    122     }
    123 }
    124 int idx(int x,int y){ return (x-1)*M+y; }
    125 void build_net()
    126 {
    127     for(int i=1;i<=N;i++)
    128     for(int j=1;j<=M;j++){
    129         int id=idx(i,j);
    130         for(int k=1;k+j<=M;k++){
    131             gp.add_edge(id+k,id);
    132             gp.rd[id]++;
    133         }
    134         for(int k=0;k<att[i][j].size();k++){
    135             int _id=idx(att[i][j][k].x,att[i][j][k].y);
    136             gp.add_edge(id,_id); gp.rd[_id]++;
    137         }
    138     }
    139     gp.n=N*M; gp.topo_sort();
    140     for(int p=1;p<=gp.np;p++){
    141         int x=gp.E[p].from,y=gp.E[p].to;
    142         if(gp.topo[x]&&gp.topo[y]) net.add_edge(y,x,net.inf);
    143     }
    144     net.n=N*M+2,net.S=net.n-1,net.T=net.n;
    145     for(int i=1;i<=N;i++)
    146     for(int j=1;j<=M;j++) if(gp.topo[idx(i,j)]){
    147         if(sco[i][j]>0) net.add_edge(net.S,idx(i,j),sco[i][j]);
    148         else if(sco[i][j]<0) net.add_edge(idx(i,j),net.T,-sco[i][j]);
    149     }
    150 }
    151 void work()
    152 {
    153     build_net();
    154     int sum=0;
    155     for(int i=1;i<=N;i++)
    156     for(int j=1;j<=M;j++)
    157         if(sco[i][j]>0&&gp.topo[idx(i,j)]) sum+=sco[i][j];
    158     printf("%d
    ",sum-net.ISAP());
    159 }
    160 int main()
    161 {
    162     data_in();
    163     work();
    164     return 0;
    165 }
  • 相关阅读:
    Nodejs定时任务(node-schedule)
    JS数组reduce()方法详解及高级技巧
    JS中的单线程与多线程、事件循环与消息队列、宏任务与微任务
    用 canvas 的 getImageData 做点有趣的事
    高并发问题处理研究:Select for update使用解析:悲观锁与乐观锁、行锁与表锁
    node项目部署正常启动后不能访问的问题
    nodejs获取formdata上传的文件及解析excel问题
    程序员居然还不会搭建一个自己的博客网站?
    10分钟带你搭建属于自己的博客
    HashMap的循环姿势你真的掌握了吗?
  • 原文地址:https://www.cnblogs.com/KKKorange/p/8552121.html
Copyright © 2011-2022 走看看