首页 > 代码库 > Bzoj1565 [NOI2009]植物大战僵尸

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\n",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 }

 

Bzoj1565 [NOI2009]植物大战僵尸