【题目地址】
http://acm.hdu.edu.cn/showproblem.php?pid=3491
【题目大意】
有n个城市和m条道路(双向),一伙thieves准备从S城出发到H城盗窃,The brave, brilliant, bright police(囧!!)为了将这伙thieves抓住,需要在这n个城市中的每一个城市安排一定数量的police(已知条件)。但police不希望在S城或H城邂逅thieves。
求总共需要的最少police数。
【解题思路】
把城市作为点拆开(把城市 i 拆成cap数组中的cap[i][i+n].其中i作为城市i的入,i+n作为城市i的出),原来的道路仍然作为边,但是边权是无穷大. 只要注意到BFS的时候 起点/终点是不需要拆的.(在cap[][]数组中就直接把起点/终点的入和出之间的边权赋值为0,使得BFS的时候不走起点/终点,实际上就相当于没有把起点/终点拆开.程序中的处理方法就是 cap[s][s+n] = 0;/cap[e][e+n] = 0;)
PS(与本题无关):HDU 3549(最大流)WA了n次,才知道两点之间可能有多条道路,cap[][]为边权之和。
题目n<=100,m<=10000,建议用SAP或Dinic求最大流,时间复杂度为O(V^2 * E)。
本题数据较弱,下面是O(V*E^2)的朴素层次图算法(实际上就是BFS。。(*^__^*) )代码:
【代码】
-
#include<cstdio>
-
#include<cstring>
-
#define inf 2147483647
-
#define maxn 201
-
int cap[maxn][maxn],que[maxn],pre[maxn],vis[maxn];
-
int s,t,n,m,h;
-
bool bfs()
-
{
-
int i,j,l=0,r=0;
-
que[r++]=s;
-
memset(vis,0,sizeof(vis));
-
while(l<r)
-
{
-
j=que[l++];
-
for(i=1;i<=2*n;i++)
-
if(!vis[i]&&cap[j][i]>0)
-
{
-
vis[i]=1;
-
pre[i]=j;
-
if(i==t)
-
return true;
-
que[r++]=i;
-
}
-
}
-
return false;
-
}
-
int maxflow()
-
{
-
int flow=0,i,min;
-
while(bfs())
-
{
-
for(i=t,min=inf;i!=s;i=pre[i])
-
if(cap[pre[i]][i]<min)
-
min=cap[pre[i]][i];
-
flow+=min;
-
for(i=t; i!=s;i=pre[i])
-
{
-
cap[pre[i]][i]-=min;
-
cap[i][pre[i]]+=min;
-
}
-
}
-
return flow;
-
}
-
int main()
-
{
-
int T,x,y,i;
-
scanf("%d", &T);
-
while(T--)
-
{
-
memset(cap,0,sizeof(cap));
-
scanf("%d%d%d%d",&n,&m,&s,&h);
-
for(i=1;i<=n;i++)
-
scanf("%d",&cap[i][i+n]);
-
s=s+n;t=h;
-
cap[h][h+n]=0;
-
cap[s][s+n]=0;
-
for(i=1;i<=m;i++)
-
{
-
scanf("%d%d",&x,&y);
-
cap[x+n][y]=inf;
-
cap[y+n][x]=inf;
-
}
-
printf("%d/n",maxflow());
-
}
-
return 0;
-
}