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 }

 

posted @ 2017-01-24 20:09  SilverNebula  阅读(313)  评论(0编辑  收藏  举报
AmazingCounters.com