BZOJ 1565: [NOI2009]植物大战僵尸
1565: [NOI2009]植物大战僵尸
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 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
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
推荐一下僧仙的题解,很好的。
这叫什么最大权闭合子图问题,额,好听死了。
首先,如果有形如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