Problem Description
输入T代表有T组测试数据,输入n, d。代表接下来的有两个矩阵n行len列(列是不知道的)。第一个矩阵每个点代表着柱子,对应的值,代表这个柱子的承受能力,青蛙从这里跳走承受能力就会–,直至0就不能承受青蛙了。第二个矩阵L代表青蛙一开始在这里,.代表没有青蛙。问你最少还有多少只青蛙不能跳出边界。每次青蛙能跳的最大距离为d。
思路
核心是能想到最大流,紧接着是建图。拆点限流流量为承受能力,因为点点之间可以到达,所以建图需要注意指向。注意输出样例。was were
#include<bits/stdc++.h>
using namespace std;
struct node
{
int to, cap, next;
};
#define inf 0x3f3f3f3f
node Map[1000000];
int head[1000], vis[1000], cnt;
char s[50][50];
void add(int u, int v, int w)//前向星存图
{
Map[cnt].to = v;
Map[cnt].cap = w;
Map[cnt].next = head[u];
head[u] = cnt++;
Map[cnt].to = u;
Map[cnt].cap = 0;
Map[cnt].next = head[v];
head[v] = cnt++;
}
bool bfs(int s, int e)
{
memset(vis, -1, sizeof(vis));
queue<int> q;
q.push(s);
vis[s] = 0;
while(!q.empty())
{
s = q.front(), q.pop();
for(int i = head[s]; ~i; i = Map[i].next)
{
int to = Map[i].to, cap = Map[i].cap;
if(vis[to] == -1 && cap)
{
vis[to] = vis[s] + 1;
q.push(to);
}
}
}
if(vis[e] == -1) return 0;
else return 1;
}
int dfs(int s, int e, int f)
{
if(s == e) return f;
int ans = 0;
for(int i = head[s]; ~i; i = Map[i].next)
{
int to = Map[i].to, &cap = Map[i].cap;
if(vis[to] > vis[s] && cap)
{
int d = dfs(to, e, min(f, cap));
if(d)
{
cap -= d;
Map[i^1].cap += d;
f -= d;
ans += d;
if(!f) break;
}
}
}
if(ans) return ans;
vis[s] = -1;
return 0;
}
int dinic(int s, int e)//求最大流
{
int ans = 0;
while(bfs(s, e))
{
ans += dfs(s, e, inf);
}
return ans;
}
double dist(node x, node y)//两点之间的距离
{
return sqrt(double((x.to - y.to)*(x.to - y.to) + (x.cap - y.cap)*(x.cap - y.cap)));
}
int main()
{
int T, Case = 1, n, m, d, i, j, len;
scanf("%d", &T);
while(T--)
{
scanf("%d %d", &n, &d);
memset(head, -1, sizeof(head));
cnt = 0;
vector<node> p, ins;
for(i = 0; i < n; i++)
{
scanf("%s", s[i]);
len = strlen(s[i]);
for(j = 0; j < len; j++)
{
if(s[i][j] != '0')
p.push_back((node){i, j, s[i][j] - '0'});//存起来所有能承受青蛙的柱子
}
}
for(i = 0; i < n; i++)
{
scanf("%s", s[i]);
for(j = 0; j < len; j++)
{
if(s[i][j] == 'L')
ins.push_back((node){i, j});//存起来所有一开始青蛙的位置
}
}
int cn = n;
n = p.size();
for(i = 0; i < n; i++)
{
add(i+1, i+n+1, p[i].next);//拆点限流
if((d - p[i].to >= 1) || (d - p[i].cap >= 1) || (len - p[i].cap <= d) || (cn - p[i].to <= d))//能直接跳出去的柱子
{
add(i+n+1, 2*n+1, inf);
}
for(j = i+1; j < n; j++)
{
double dis = dist(p[i], p[j]);
if(dis > d) continue;
add(i+n+1, j+1, inf);//点点之间能够到达的建边 并且双向
add(j+n+1, i+1, inf);
}
}
m = ins.size();
for(i = 0; i < m; i++)
{
for(j = 0; j < n; j++)
{
if(p[j].to == ins[i].to && p[j].cap == ins[i].cap)//一开始 有青蛙的点
add(0, j+1, 1);
}
}
int ans = dinic(0, 2*n+1);//求最大流,最后注意输出格式
if(ans == m) printf("Case #%d: no lizard was left behind.\n", Case++);
else if(ans == m - 1) printf("Case #%d: 1 lizard was left behind.\n", Case++);
else
printf("Case #%d: %d lizards were left behind.\n", Case++, m - ans);
}
}