BZOJ 1565: [NOI2009]植物大战僵尸

1565: [NOI2009]植物大战僵尸

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 2318  Solved: 1072
[Submit][Status][Discuss]

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

 
[ Submit][ Status][ Discuss]

 

 

推荐一下僧仙的题解,很好的。

 

这叫什么最大权闭合子图问题,额,好听死了。

首先,如果有形如A保护B,B保护A这样的扯淡关系,那么A和B都不能吃。

按照保护关系建出有向图后拓扑排序可以筛出这些顽强的植物,并把它们从题中永久删除。

可以把最终得分,转换为所有正权之和,减去选取的负权之和,减去未选取的正权之和,咦,这东西可以最小割了……

 

  1 #include <cstdio>
  2 #include <cstring>
  3 
  4 inline int nextChar(void)
  5 {
  6     const static int siz = 1024;
  7     
  8     static char buf[siz];
  9     static char *hd = buf + siz;
 10     static char *tl = buf + siz;
 11     
 12     if (hd == tl)
 13         fread(hd = buf, 1, siz, stdin);
 14         
 15     return *hd++;
 16 }
 17 
 18 inline int nextInt(void)
 19 {
 20     register int ret = 0;
 21     register int neg = false;
 22     register int bit = nextChar();
 23     
 24     for (; bit < 48; bit = nextChar())
 25         if (bit == '-')neg ^= true;
 26         
 27     for (; bit > 47; bit = nextChar())
 28         ret = ret * 10 + bit - 48;
 29         
 30     return neg ? -ret : ret;
 31 }
 32 
 33 const int siz = 500005;
 34 const int inf = 1000000007;
 35 
 36 int n, m;
 37 int S[1005];
 38 int P[55][55];
 39 
 40 inline void getP(void)
 41 {
 42     int tot = 0;
 43     
 44     for (int i = 1; i <= n; ++i)
 45         for (int j = 1; j <= m; ++j)
 46             P[i][j] = ++tot;
 47 }
 48 
 49 namespace flow
 50 {
 51     int s, t;
 52     int hd[siz];
 53     int nt[siz];
 54     int fl[siz];
 55     int to[siz];
 56     
 57     int dep[siz];
 58     
 59     inline bool bfs(void)
 60     {
 61         static int que[siz], head, tail;
 62         memset(dep, 0, sizeof(dep));
 63         head = 0, tail = 0;
 64         que[tail++] = s;
 65         dep[s] = 1;
 66         
 67         while (head != tail)
 68         {
 69             int u = que[head++], v;
 70             
 71             for (int i = hd[u]; ~i; i = nt[i])
 72                 if (!dep[v = to[i]] && fl[i])
 73                     dep[que[tail++] = v] = dep[u] + 1;
 74         }
 75         
 76         return dep[t];
 77     }
 78     
 79     int cur[siz];
 80     
 81     int dfs(int u, int f)
 82     {
 83         if (u == t || !f)
 84             return f;
 85             
 86 //        printf("dfs %d %d\n", u, f);
 87         
 88         int used = 0, flow, v;
 89         
 90         for (int i = hd[u]; ~i; i = nt[i])
 91             if (dep[v = to[i]] == dep[u] + 1 && fl[i])    
 92             {
 93                 if (f - used < fl[i])
 94                     flow = dfs(v, f - used);
 95                 else
 96                     flow = dfs(v, fl[i]);
 97                 
 98                 used += flow;
 99                 fl[i] -= flow;
100                 fl[i^1] += flow;
101                 
102                 if (used == f)
103                     return f;
104                     
105                 if (fl[i])
106                     cur[u] = i;
107             }
108         
109         if (!used)
110             dep[u] = 0;
111             
112         return used;
113     }
114     
115     inline int solve(void)
116     {
117         int maxFlow = 0, newFlow;
118         
119         while (bfs())
120         {
121             for (int i = s; i <= t; ++i)
122                 cur[i] = hd[i];
123             while (newFlow = dfs(s, inf))
124                 maxFlow += newFlow;
125         }
126         
127         return maxFlow;
128     }
129 }
130 
131 inline void add(int u, int v, int f)
132 {
133 //    printf("add %d %d %d\n", u, v, f);
134     
135     using namespace flow;
136     
137     static int tot = 0;
138     static int flg = 0;
139     
140     if (!flg)
141         memset(hd, -1, sizeof(hd)), flg = 1;
142         
143     nt[tot] = hd[u]; to[tot] = v; fl[tot] = f; hd[u] = tot++;
144     nt[tot] = hd[v]; to[tot] = u; fl[tot] = 0; hd[v] = tot++;
145 }
146 
147 namespace turpo
148 {
149     int hd[siz];
150     int to[siz];
151     int nt[siz];
152     int cnt[siz];
153     int vis[siz];
154     
155     inline void solve(void)
156     {
157         static int que[siz], head, tail;
158         
159         for (int i = 1; i <= P[n][m]; ++i)
160             if (!cnt[i])que[tail++] = i;
161             
162         while (head != tail)
163         {
164             int u = que[head++], v;
165             
166             vis[u] = true;
167             
168             for (int i = hd[u]; ~i; i = nt[i])
169                 if (--cnt[v = to[i]] == 0)que[tail++] = v;
170         }
171         
172 //        for (int i = 1; i <= P[n][m]; ++i)
173 //            printf("%d : %d\n", i, vis[i]);
174         
175         for (int i = 1; i <= P[n][m]; ++i)
176             for (int j = hd[i]; ~j; j = nt[j])
177                 if (vis[i] && vis[to[j]])
178                     add(to[j], i, inf);
179     }
180 }
181 
182 inline void addEdge(int u, int v)
183 {
184 //    printf("addEdge %d %d\n", u, v);
185     
186     using namespace turpo;
187     
188     static int tot = 0;
189     static int flg = 0;
190     
191     if (!flg)
192         memset(hd, -1, sizeof(hd)), flg = 1;
193     
194     nt[tot] = hd[u]; to[tot] = v; hd[u] = tot++; ++cnt[v];
195 }
196 
197 signed main(void)
198 {
199     n = nextInt();
200     m = nextInt();
201     
202     int sum = 0;
203     
204     getP();
205     
206     for (int i = 1; i <= n; ++i)
207         for (int j = 1; j <= m; ++j)
208         {
209             S[P[i][j]] = nextInt();
210             
211             for (int k = nextInt(); k--; )
212             {
213                 int x = nextInt() + 1;
214                 int y = nextInt() + 1;
215                 
216                 addEdge(P[i][j], P[x][y]);
217             }
218             
219             if (j > 1)
220                 addEdge(P[i][j], P[i][j - 1]);
221         }
222         
223     turpo::solve();
224     
225     flow::s = 0;
226     flow::t = P[n][m] + 1;
227     
228     for (int i = 1; i <= P[n][m]; ++i)
229         if (turpo::vis[i])
230         {
231             if (S[i] < 0)
232                 add(i, flow::t, -S[i]);
233             else
234                 add(flow::s, i, S[i]), sum += S[i];
235         }
236         
237     printf("%d\n", sum - flow::solve());
238 }

 

@Author: YouSiki

 

转载于:https://www.cnblogs.com/yousiki/p/6259802.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值