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了,把恒存在的植物环的所有出边给删了……
#include<bits/stdc++.h>
const int maxn = ;
const int maxNode = ;
const int maxm = ;
const int INF = 2e9; struct Edge
{
int u,v,f,c;
Edge(int a=, int b=, int c=, int d=):u(a),v(b),f(c),c(d) {}
}edges[maxm];
int r,c,S,T,ans;
int v[maxn][maxn],id[maxn][maxn];
int edgeTot,head[maxNode],nxt[maxm],lv[maxNode];
int low[maxNode],dfn[maxNode],tim;
int stk[maxNode],top,col[maxNode],cols,size[maxNode]; int read()
{
char ch = getchar();
int num = , fl = ;
for (; !isdigit(ch); ch=getchar())
if (ch=='-') fl = -;
for (; isdigit(ch); ch=getchar())
num = (num<<)+(num<<)+ch-;
return num*fl;
}
void addedge(int u, int v, int c)
{
edges[edgeTot] = Edge(u, v, , c), nxt[edgeTot] = head[u], head[u] = edgeTot, ++edgeTot;
edges[edgeTot] = Edge(v, u, , ), nxt[edgeTot] = head[v], head[v] = edgeTot, ++edgeTot;
}
bool buildLevel()
{
std::queue<int> q;
memset(lv, , sizeof lv);
q.push(S), lv[S] = ;
for (int tmp; q.size(); )
{
tmp = q.front(), q.pop();
for (int i=head[tmp]; i!=-; i=nxt[i])
{
int v = edges[i].v;
if (!lv[v]&&edges[i].f < edges[i].c){
lv[v] = lv[tmp]+, q.push(v);
if (v==T) return true;
}
}
}
return false;
}
int fndPath(int x, int lim)
{
int sum = ;
if (x==T||!lim) return lim;
for (int i=head[x]; i!=-&&sum < lim; i=nxt[i])
{
int v = edges[i].v, val;
if (lv[v]==lv[x]+&&edges[i].f < edges[i].c){
if ((val = fndPath(v, std::min(lim-sum, edges[i].c-edges[i].f)))){
sum += val, edges[i].f += val, edges[i^].f -= val;
}else lv[v] = -;
}
}
return sum;
}
int dinic()
{
int ret = , val;
while (buildLevel())
while ((val = fndPath(S, INF))) ret += val;
return ret;
}
void tarjan(int x)
{
dfn[x] = low[x] = ++tim, stk[++top] = x;
for (int i=head[x]; i!=-; i=nxt[i])
if ((i&)==){
int v = edges[i].v;
if (!dfn[v]) tarjan(v), low[x] = std::min(low[x], low[v]);
else if (!col[v]) low[x] = std::min(low[x], dfn[v]);
}
if (low[x]==dfn[x]){
col[x] = ++cols, size[cols] = ;
for (; stk[top]!=x; --top)
col[stk[top]] = cols, ++size[cols];
--top;
}
}
int main()
{
memset(head, -, sizeof head);
r = read(), c = read(), S = , T = r*c+;
for (int i=, cnt=; i<=r; i++)
for (int j=; j<=c; j++)
id[i][j] = ++cnt;
for (int i=; i<=r; i++)
for (int j=; j<=c; j++)
{
v[i][j] = read();
if (j!=c) addedge(id[i][j], id[i][j+], INF);
for (int k=read(); k; k--)
addedge(id[read()+][read()+], id[i][j], INF);
}
for (int i=; i<=r*c; i++)
if (!dfn[i]) tarjan(i);
for (int i=; i<=r; i++)
for (int j=; j<=c; j++)
if (size[col[id[i][j]]]==){
if (v[i][j] < ) addedge(id[i][j], T, -v[i][j]);
else addedge(S, id[i][j], v[i][j]), ans += v[i][j];
}
printf("%d\n",ans-dinic());
return ;
}
END