zoukankan      html  css  js  c++  java
  • Bzoj1565 [NOI2009]植物大战僵尸

    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 2363  Solved: 1092

    Description

    Input

    Output

    仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。

    Sample Input

    3 2
    10 0
    20 0
    -10 0
    -5 1 0 0
    100 1 2 1
    100 0

    Sample Output

    25

    HINT

    在样例中, 植物P1,1可以攻击位置(0,0), P2, 0可以攻击位置(2,1)。 
    一个方案为,首先进攻P1,1, P0,1,此时可以攻击P0,0 。共得到能源收益为(-5)+20+10 = 25。注意, 位置(2,1)被植物P2,0保护,所以无法攻击第2行中的任何植物。 
    【大致数据规模】
    约20%的数据满足1 ≤ N, M ≤ 5;
    约40%的数据满足1 ≤ N, M ≤ 10;
    约100%的数据满足1 ≤ N ≤ 20,1 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000 。

    Source

    网络流+拓扑排序

    因为植物可能会互相保护而形成环,所以先用拓扑排序排除环,求出图中的闭合子图。

    然后按照先吃右边才能吃左边的关系,从每个点向它左边一格的点连边,容量为INF

    保护型的植物向它保护的植物连边,容量为INF。

    吃植物能获得收益时,该植物向汇点连边,容量为收益。

    吃植物需要代价时,源点向该植物连边,容量为代价的绝对值。

    答案=可能获得的收益总和-最小割。

      1 /*by SilverN*/
      2 #include<algorithm>
      3 #include<iostream>
      4 #include<cstring>
      5 #include<cstdio>
      6 #include<cmath>
      7 #include<vector>
      8 #include<queue>
      9 using namespace std;
     10 const int mx[5]={0,1,0,-1,0};
     11 const int my[5]={0,0,1,0,-1};
     12 const int INF=1e9;
     13 const int mxn=2010;
     14 int read(){
     15     int x=0,f=1;char ch=getchar();
     16     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     17     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
     18     return x*f;
     19 }
     20 struct edge{
     21     int v,nxt,f;
     22 }e[mxn*500];
     23 int hd[mxn],mct=1;
     24 void add_edge(int u,int v,int f){
     25     e[++mct].v=v;e[mct].nxt=hd[u];e[mct].f=f;hd[u]=mct;return;
     26 }
     27 void insert(int u,int v,int f){
     28     add_edge(u,v,f);add_edge(v,u,0);return;
     29 }
     30 vector<int>eg[mxn];
     31 int n,m,S,T;
     32 int d[mxn];
     33 bool BFS(){
     34     memset(d,0,sizeof d);
     35     queue<int>q;
     36     d[S]=1;
     37     q.push(S);
     38     while(!q.empty()){
     39         int u=q.front();q.pop();
     40         for(int i=hd[u];i;i=e[i].nxt){
     41             int v=e[i].v;
     42             if(e[i].f && !d[v]){
     43                 d[v]=d[u]+1;
     44                 q.push(v);
     45             }
     46         }
     47     }
     48     return d[T];
     49 }
     50 int DFS(int u,int lim){
     51     if(u==T)return lim;
     52     int f=0,tmp;
     53     for(int i=hd[u];i;i=e[i].nxt){
     54         int v=e[i].v;
     55         if(d[v]==d[u]+1 && e[i].f && (tmp=DFS(v,min(lim,e[i].f)))){
     56             e[i].f-=tmp;   e[i^1].f+=tmp;
     57             f+=tmp;        lim-=tmp;
     58             if(!lim)return f;
     59         }
     60     }
     61     d[u]=0;
     62     return f;
     63 }
     64 int Dinic(){
     65     int res=0;
     66     while(BFS())res+=DFS(S,INF);
     67     return res;
     68 }
     69 int id[50][50],cnt=0,ed;
     70 void init(){
     71     for(int i=1;i<=n;i++)
     72      for(int j=1;j<=m;j++)
     73          id[i][j]=++cnt;
     74     ed=n*m;
     75     return;
     76 }
     77 int sc[mxn];
     78 int ind[mxn];
     79 int st[mxn],top=0;
     80 bool vis[mxn];
     81 void topo(){//拓扑排序,判断植物能否攻击 
     82     int i,j,res=0;
     83     for(i=1;i<=cnt;i++)
     84         if(!ind[i])st[++top]=i;
     85     while(top){
     86         int u=st[top--];
     87         vis[u]=1;
     88         if(sc[u]>0){
     89             res+=sc[u];
     90             insert(u,T,sc[u]);//可能得到的分数 
     91         }
     92         else  insert(S,u,-sc[u]);//需要付出的代价 
     93         for(j=0;j<eg[u].size();j++){
     94             int v=eg[u][j];
     95             ind[v]--;
     96             insert(u,v,INF);
     97             if(!ind[v])st[++top]=v;
     98         }
     99     }
    100     for(i=1;i<=n;i++)
    101         for(j=2;j<=m;j++){
    102             if(vis[id[i][j]] && vis[id[i][j-1]]){//先吃右面再吃左面 
    103                 insert(id[i][j],id[i][j-1],INF);
    104             }
    105         }
    106     res=res-Dinic();
    107     printf("%d
    ",res);
    108 }
    109 int main(){
    110     int i,j,w,x,y;
    111     n=read();m=read();
    112     init();
    113     S=0;T=ed+1;
    114     for(i=1;i<=n;i++){
    115         for(j=1;j<=m;j++){
    116             sc[id[i][j]]=read();
    117             w=read();
    118             while(w--){
    119                 x=read()+1;y=read()+1;
    120                 eg[id[i][j]].push_back(id[x][y]);
    121                 ind[id[x][y]]++;
    122             }
    123             if(j>1){//先解锁右面的才能吃左面的 
    124                 eg[id[i][j]].push_back(id[i][j-1]);
    125                 ind[id[i][j-1]]++;
    126             }
    127         }
    128     }
    129     topo();
    130     return 0;
    131 }
  • 相关阅读:
    aws亚马逊配置 https,操作步骤记录
    八年phper的高级工程师面试之路八年phper的高级工程师面试之路
    laravel 获取目录下的所有目录Storage::directories
    Docker 入门看这一篇就够了,万字详解!
    PHP 引用是个坑,请慎用
    php面试常问方法汇总
    注册、登录和 token 的安全之道
    分享一下最近的面试题,都是大厂
    Xpath2
    ActiveX控件的实现
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6347759.html
Copyright © 2011-2022 走看看