dinic+tarjan板子练手题
Description
Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏。Plants(植物)和Zombies(僵尸)是游戏的主角,其
中Plants防守,而Zombies进攻。该款游戏包含多种不同的挑战系列,比如Protect Your Brain、Bowling等等。其
中最为经典的,莫过于玩家通过控制Plants来防守Zombies的进攻,或者相反地由玩家通过控制Zombies对Plants发
起进攻。
现在,我们将要考虑的问题是游戏中Zombies对Plants的进攻,请注意,本题中规则与实际游戏有所不同。游戏中
有两种角色,Plants和Zombies,每个Plant有一个攻击位置集合,它可以对这些位置进行保护;而Zombie进攻植物
的方式是走到植物所在的位置上并将其吃掉。
游戏的地图可以抽象为一个N行M列的矩阵,行从上到下用0到N–1编号,列从左到右用0到M–1编号;在地图的每个
位置上都放有一个Plant,为简单起见,我们把位于第r行第c列的植物记为Pr, c。
Plants分很多种,有攻击类、防守类和经济类等等。为了简单的描述每个Plant,定义Score和Attack如下:
Score[Pr, c]
Zombie击溃植物Pr, c可获得的能源。若Score[Pr, c]为非负整数,则表示击溃植物Pr, c可获得能源Score[Pr, c]
,若为负数表示击溃Pr, c需要付出能源 -Score[Pr, c]。
Attack[Pr, c]
植物Pr, c能够对Zombie进行攻击的位置集合。
Zombies必须从地图的右侧进入,且只能沿着水平方向进行移动。Zombies攻击植物的唯一方式就是走到该植物所在
的位置并将植物吃掉。因此Zombies的进攻总是从地图的右侧开始。也就是说,对于第r行的进攻,Zombies必须首
先攻击Pr, M-1;若需要对Pr, c(0 ≤ c < M-1)攻击,必须将Pr,M-1, Pr, M-2 … Pr, c+1先击溃,并移动到位
置(r, c)才可进行攻击。
在本题的设定中,Plants的攻击力是无穷大的,一旦Zombie进入某个Plant的攻击位置,该Zombie会被瞬间消灭,
而该Zombie没有时间进行任何攻击操作。因此,即便Zombie进入了一个Plant所在的位置,但该位置属于其他植物
的攻击位置集合,则Zombie会被瞬间消灭而所在位置的植物则安然无恙(在我们的设定中,Plant的攻击位置不包
含自身所在位置,否则你就不可能击溃它了)。
Zombies的目标是对Plants的阵地发起进攻并获得最大的能源收入。每一次,你可以选择一个可进攻的植物进行攻
击。本题的目标为,制定一套Zombies的进攻方案,选择进攻哪些植物以及进攻的顺序,从而获得最大的能源收入
。
Input
第一行包含两个整数N, M,分别表示地图的行数和列数。
接下来N×M行描述每个位置上植物的信息。第r×M + c + 1行按照如下格式给出植物Pr, c的信息:
第一个整数为Score[Pr, c], 第二个整数为集合Attack[Pr, c]中的位置个数w,
接下来w个位置信息(r’, c’),表示Pr, c可以攻击位置第r’ 行第c’ 列。
1 ≤ N ≤ 20,1 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000 。
Output
仅包含一个整数,表示可以获得的最大能源收入。
注意,你也可以选择不进行任何攻击,这样能源收入为0。
题目大意
每种植物有若干个可保护的点,且僵尸消灭每种植物都会有特定权值。僵尸必须从右边进入,依次消灭没有被任何植物植物保护的植物。求僵尸能够获得的最大价值。
题目分析
放上来当板子看吧
第一发写的时候zz了,把恒存在的植物环的所有出边给删了……
1 #include<bits/stdc++.h> 2 const int maxn = 33; 3 const int maxNode = 5035; 4 const int maxm = 1000035; 5 const int INF = 2e9; 6 7 struct Edge 8 { 9 int u,v,f,c; 10 Edge(int a=0, int b=0, int c=0, int d=0):u(a),v(b),f(c),c(d) {} 11 }edges[maxm]; 12 int r,c,S,T,ans; 13 int v[maxn][maxn],id[maxn][maxn]; 14 int edgeTot,head[maxNode],nxt[maxm],lv[maxNode]; 15 int low[maxNode],dfn[maxNode],tim; 16 int stk[maxNode],top,col[maxNode],cols,size[maxNode]; 17 18 int read() 19 { 20 char ch = getchar(); 21 int num = 0, fl = 1; 22 for (; !isdigit(ch); ch=getchar()) 23 if (ch=='-') fl = -1; 24 for (; isdigit(ch); ch=getchar()) 25 num = (num<<1)+(num<<3)+ch-48; 26 return num*fl; 27 } 28 void addedge(int u, int v, int c) 29 { 30 edges[edgeTot] = Edge(u, v, 0, c), nxt[edgeTot] = head[u], head[u] = edgeTot, ++edgeTot; 31 edges[edgeTot] = Edge(v, u, 0, 0), nxt[edgeTot] = head[v], head[v] = edgeTot, ++edgeTot; 32 } 33 bool buildLevel() 34 { 35 std::queue<int> q; 36 memset(lv, 0, sizeof lv); 37 q.push(S), lv[S] = 1; 38 for (int tmp; q.size(); ) 39 { 40 tmp = q.front(), q.pop(); 41 for (int i=head[tmp]; i!=-1; i=nxt[i]) 42 { 43 int v = edges[i].v; 44 if (!lv[v]&&edges[i].f < edges[i].c){ 45 lv[v] = lv[tmp]+1, q.push(v); 46 if (v==T) return true; 47 } 48 } 49 } 50 return false; 51 } 52 int fndPath(int x, int lim) 53 { 54 int sum = 0; 55 if (x==T||!lim) return lim; 56 for (int i=head[x]; i!=-1&&sum < lim; i=nxt[i]) 57 { 58 int v = edges[i].v, val; 59 if (lv[v]==lv[x]+1&&edges[i].f < edges[i].c){ 60 if ((val = fndPath(v, std::min(lim-sum, edges[i].c-edges[i].f)))){ 61 sum += val, edges[i].f += val, edges[i^1].f -= val; 62 }else lv[v] = -1; 63 } 64 } 65 return sum; 66 } 67 int dinic() 68 { 69 int ret = 0, val; 70 while (buildLevel()) 71 while ((val = fndPath(S, INF))) ret += val; 72 return ret; 73 } 74 void tarjan(int x) 75 { 76 dfn[x] = low[x] = ++tim, stk[++top] = x; 77 for (int i=head[x]; i!=-1; i=nxt[i]) 78 if ((i&1)==0){ 79 int v = edges[i].v; 80 if (!dfn[v]) tarjan(v), low[x] = std::min(low[x], low[v]); 81 else if (!col[v]) low[x] = std::min(low[x], dfn[v]); 82 } 83 if (low[x]==dfn[x]){ 84 col[x] = ++cols, size[cols] = 1; 85 for (; stk[top]!=x; --top) 86 col[stk[top]] = cols, ++size[cols]; 87 --top; 88 } 89 } 90 int main() 91 { 92 memset(head, -1, sizeof head); 93 r = read(), c = read(), S = 0, T = r*c+1; 94 for (int i=1, cnt=0; i<=r; i++) 95 for (int j=1; j<=c; j++) 96 id[i][j] = ++cnt; 97 for (int i=1; i<=r; i++) 98 for (int j=1; j<=c; j++) 99 { 100 v[i][j] = read(); 101 if (j!=c) addedge(id[i][j], id[i][j+1], INF); 102 for (int k=read(); k; k--) 103 addedge(id[read()+1][read()+1], id[i][j], INF); 104 } 105 for (int i=1; i<=r*c; i++) 106 if (!dfn[i]) tarjan(i); 107 for (int i=1; i<=r; i++) 108 for (int j=1; j<=c; j++) 109 if (size[col[id[i][j]]]==1){ 110 if (v[i][j] < 0) addedge(id[i][j], T, -v[i][j]); 111 else addedge(S, id[i][j], v[i][j]), ans += v[i][j]; 112 } 113 printf("%d\n",ans-dinic()); 114 return 0; 115 }
END