UVA 563 Crimewave

UVA_563

    这个题目我们可以引入一个源点与抢劫点相连,引入一个汇点和逃脱的各点相连,然后看最大流是否和抢劫点的数量相等即可。

由于限制了每个点的容量为1,因此我们可以对每个点进行拆点,然后两点之间连一条容量为1的有向边。

#include<stdio.h>
#include<string.h>
#define MAXD 7200
#define MAXM 36000
#define INF 1000000000
int S, A, B, e, first[MAXD], next[MAXM], u[MAXM], v[MAXM], flow[MAXM];
int d[MAXD], q[MAXD], s[MAXD], work[MAXD];
void add(int x, int y, int f)
{
u[e] = x;
v[e] = y;
flow[e] = f;
next[e] = first[x];
first[x] = e;
e ++;
}
void init()
{
int i, j, k, x, y, z, newz;
memset(first, -1, sizeof(first));
e = 0;
scanf("%d%d%d", &S, &A, &B);
for(i = 1; i <= A; i ++)
{
z = A + i;
add(2 * z ^ 1, 1, 1);
add(1, 2 * z ^ 1, 0);
}
for(i = 1; i <= S; i ++)
{
z = i * A + 1;
add(2 * z ^ 1, 1, 1);
add(1, 2 * z ^ 1, 0);
}
for(i = 1; i <= A; i ++)
{
z = S * A + i;
add(2 * z ^ 1, 1, 1);
add(1, 2 * z ^ 1, 0);
}
for(i = 1; i <= S; i ++)
{
z = i * A + A;
add(2 * z ^ 1, 1, 1);
add(1, 2 * z ^ 1, 0);
}
for(i = 1; i <= S; i ++)
for(j = 1; j <= A; j ++)
{
z = i * A + j;
add(2 * z, 2 * z ^ 1, 1);
add(2 * z ^ 1, 2 * z, 0);
if(i + 1 <= S)
{
newz = (i + 1) * A + j;
add(2 * z ^ 1, 2 * newz, 1);
add(2 * newz, 2 * z ^ 1, 0);
add(2 * newz ^ 1, 2 * z, 1);
add(2 * z, 2 * newz ^ 1, 0);
}
if(j + 1 <= A)
{
newz = i * A + j + 1;
add(2 * z ^ 1, 2 * newz, 1);
add(2 * newz, 2 * z ^ 1, 0);
add(2 * newz ^ 1, 2 * z, 1);
add(2 * z, 2 * newz ^ 1, 0);
}
}
for(i = 0; i < B; i ++)
{
scanf("%d%d", &x, &y);
z = x * A + y;
add(0, 2 * z, 1);
add(2 * z, 0, 0);
}
}
int bfs()
{
int i, j, rear;
memset(d, -1, sizeof(d));
d[0] = 0;
rear = 0;
q[rear ++] = 0;
for(i = 0; i < rear; i ++)
for(j = first[q[i]]; j != -1; j = next[j])
if(flow[j] && d[v[j]] == -1)
{
d[v[j]] = d[q[i]] + 1;
if(v[j] == 1)
return 1;
q[rear ++] = v[j];
}
return 0;
}
int dinic()
{
int i, j, r, cur, res = 0;
while(bfs())
{
r = 0;
cur = 0;
memcpy(work, first, sizeof(first));
for(;;)
{
if(cur == 1)
{
int a = INF, minr = r;
for(i = 0; i < r; i ++)
if(flow[s[i]] < a)
{
a = flow[s[i]];
minr = i;
}
for(i = 0; i < r; i ++)
{
flow[s[i]] -= a;
flow[s[i] ^ 1] += a;
}
res += a;
r = minr;
cur = u[s[r]];
continue;
}
for(i = work[cur]; i != -1; i = next[i])
if(flow[i] && d[v[i]] == d[cur] + 1)
break;
work[cur] = i;
if(i != -1)
{
s[r ++] = i;
cur = v[i];
}
else
{
d[cur] = -1;
if(r == 0)
break;
r --;
cur = u[s[r]];
}
}
}
if(res == B)
return 1;
else
return 0;
}
int main()
{
int t;
scanf("%d", &t);
while(t --)
{
init();
int ok = dinic();
if(ok)
printf("possible\n");
else
printf("not possible\n");
}
return 0;
}


转载于:https://www.cnblogs.com/staginner/archive/2011/10/25/2224300.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值