HDU3491 Thieves(最小割)

题目大概说,一个国家有n个城市,由m条双向路相连,小偷们从城市s出发准备到h城市,警察准备在某些除了s和h外的城市布置警力抓小偷,各个城市各有警力所需的数目。问警察最少要布置多少警力才能万无一失地抓住所有小偷。

相当于就是用最小的花费让s到达不了h。这么建容量网络:

每个城市拆点连容量为需要警力数量的边,源点为s‘,汇点为h,原图双向边的容量设为INF。

最小割就是答案了。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<algorithm>
  5 using namespace std;
  6 #define INF (1<<30)
  7 #define MAXN 222
  8 #define MAXM 44444
  9 struct Edge{
 10     int v,cap,flow,next;
 11 }edge[MAXM];
 12 int vs,vt,NV,NE,head[MAXN];
 13 void addEdge(int u,int v,int cap){
 14     edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=0;
 15     edge[NE].next=head[u]; head[u]=NE++;
 16     edge[NE].v=u; edge[NE].cap=0; edge[NE].flow=0;
 17     edge[NE].next=head[v]; head[v]=NE++;
 18 }
 19 int level[MAXN];
 20 int gap[MAXN];
 21 void bfs(){
 22     memset(level,-1,sizeof(level));
 23     memset(gap,0,sizeof(gap));
 24     level[vt]=0;
 25     gap[level[vt]]++;
 26     queue<int> que;
 27     que.push(vt);
 28     while(!que.empty()){
 29         int u=que.front(); que.pop();
 30         for(int i=head[u]; i!=-1; i=edge[i].next){
 31             int v=edge[i].v;
 32             if(level[v]!=-1) continue;
 33             level[v]=level[u]+1;
 34             gap[level[v]]++;
 35             que.push(v);
 36         }
 37     }
 38 }
 39 int pre[MAXN];
 40 int cur[MAXN];
 41 int ISAP(){
 42     bfs();
 43     memset(pre,-1,sizeof(pre));
 44     memcpy(cur,head,sizeof(head));
 45     int u=pre[vs]=vs,flow=0,aug=INF;
 46     gap[0]=NV;
 47     while(level[vs]<NV){
 48         bool flag=false;
 49         for(int &i=cur[u]; i!=-1; i=edge[i].next){
 50             int v=edge[i].v;
 51             if(edge[i].cap!=edge[i].flow && level[u]==level[v]+1){
 52                 flag=true;
 53                 pre[v]=u;
 54                 u=v;
 55                 aug=min(aug,edge[i].cap-edge[i].flow);
 56                 if(v==vt){
 57                     flow+=aug;
 58                     for(u=pre[v]; v!=vs; v=u,u=pre[u]){
 59                         edge[cur[u]].flow+=aug;
 60                         edge[cur[u]^1].flow-=aug;
 61                     }
 62                     aug=INF;
 63                 }
 64                 break;
 65             }
 66         }
 67         if(flag) continue;
 68         int minlevel=NV;
 69         for(int i=head[u]; i!=-1; i=edge[i].next){
 70             int v=edge[i].v;
 71             if(edge[i].cap!=edge[i].flow && level[v]<minlevel){
 72                 minlevel=level[v];
 73                 cur[u]=i;
 74             }
 75         }
 76         if(--gap[level[u]]==0) break;
 77         level[u]=minlevel+1;
 78         gap[level[u]]++;
 79         u=pre[u];
 80     }
 81     return flow;
 82 }
 83 int main(){
 84     int t,n,m,s,h,a,b;
 85     scanf("%d",&t);
 86     while(t--){
 87         scanf("%d%d%d%d",&n,&m,&s,&h);
 88         vs=s+n; vt=h; NV=n*2+1; NE=0;
 89         memset(head,-1,sizeof(head));
 90         for(int i=1; i<=n; ++i){
 91             scanf("%d",&a);
 92             addEdge(i,i+n,a);
 93         }
 94         while(m--){
 95             scanf("%d%d",&a,&b);
 96             addEdge(a+n,b,INF);
 97             addEdge(b+n,a,INF);
 98         }
 99         printf("%d\n",ISAP());
100     }
101     return 0;
102 }
时间: 2024-10-29 21:23:17

HDU3491 Thieves(最小割)的相关文章

URAL 1277 Cops and Thieves 最小割 无向图点带权点连通度

Cops and Thieves Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice URAL 1277 Appoint description: Description The Galaxy Police (Galaxpol) found out that a notorious gang of thieves has plans for stea

hdoj 3491 Thieves 【最小割 + 拆点】

题目:hdoj 3491 Thieves 题意:给出一个无向图,然后有个出发城市s,结束城市 t ,然后每个点有流量限制,问你最少用多少的人能够使得 s 到 t 没有流量. 分析:题意是抽象出来的,但是很明显看出来是求最小割.难点有2 1:无向图,所以要建双向边 2:点有流量限制,所以要拆点,拆成两个点,然后这两点的容量为点的限制,图中点的连接设置流量为inf,保证割不掉,只能从点之间割. AC代码: #include <cstdio> #include <cstring> #in

Thieves (hdu 3491 拆点 最小割)

Thieves Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 1453    Accepted Submission(s): 651 Problem Description In the kingdom of Henryy, there are N (2 <= N <= 100) cities, with M (M <= 10

Ural 1277 cops ans thieves (最小割模型)

题目地址 :http://acm.timus.ru/problem.aspx?space=1&num=1277 这里我们要拆点.把一个点拆成i,i' .如何 i,j有边 ,在建边(i,j',inf),(j,i',inf). 然后每个点点边(i',i,R[i]).这样建边以后,若要阻止 s到f的路径,那么必须破败一些边,那么我们为了是的边权最小,必须破坏边权小于inf的边,对应的就是图中拆点后的边(j'->j)  .实际上 这条边就代表了点j的点权.求最小割即是答案. 有一个需要注意的地方那个

hdu 3870(平面图最小割转最短路)

Catch the Theves Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 65768/32768 K (Java/Others)Total Submission(s): 1640    Accepted Submission(s): 514 Problem Description A group of thieves is approaching a museum in the country of zjsxzy,now t

poj 1815 Friendship 最小割输出最小方案

这题卡了好久啊,最小割模型很容易想,拆点就行.就像poj的Thieves一样 每个点 a拆成 a->a',容量为1. 其他相连的点 a'->b ,容量为INF 源连接s',t连接汇 问题在于输出最小的割集 更好的方法我还不会,只能枚举. 这里基于贪心的思想,从小到大删边, 若删除i->i',会使得最小割变小,则输出i,并且i->i'这条边不要恢复 若最小割不变,则恢复这条边,继续枚举. 一开始就是因为恢复了要割去的边,无限WA. #include<cstdio> #in

【BZOJ2039】【2009国家集训队】人员雇佣 [最小割]

人员雇佣 Time Limit: 20 Sec  Memory Limit: 259 MB[Submit][Status][Discuss] Description 作为一个富有经营头脑的富翁,小L决定从本国最优秀的经理中雇佣一些来经营自己的公司.这些经理相互之间合作有一个贡献指数,(我们用Ei,j表示i经理对j经理的了解程度),即当经理i和经理j同时被雇佣时,经理i会对经理j做出贡献,使得所赚得的利润增加Ei,j.当然,雇佣每一个经理都需要花费一定的金钱Ai,对于一些经理可能他做出的贡献不值得

hdoj 4289 Control 【拆点 求最小割】

Control Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2295    Accepted Submission(s): 961 Problem Description You, the head of Department of Security, recently received a top-secret informati

There is a war (hdu 2435 最小割+枚举)

There is a war Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 970    Accepted Submission(s): 277 Problem Description There is a sea. There are N islands in the sea. There are some directional