HDU 3491 最小点权割集

题意:有n个城市,m条双向边,有一群小偷从s前往t偷东西,警察叔叔们想要逮捕小偷们,现在告诉你在每座城市需要多少警察才能抓住这个城市的小偷,为什么说这个城市,因为小偷们会分开跑;然后题目还说不能在s和t逮捕小偷。问需要的最少警力是多少?

分析:这个问题可以变成这样:需要在哪些城市部署警力才能使得小偷不能从s到达t,也即最小点权割集。根据最小割=最大流(此处的最小割是指边权),我们可以这样建图。

建图:把除了s和t的每一个点拆开,在它们之间连一条单向边,权值为该点需要的警力。s和t同样拆开,不过权值为无穷大,因为题目说了不能在s和t逮捕。题目给出的边就按双向边相连,不过起点应该是这个点拆开后的终点,权值为无穷大。最后为了方便,可以把源点和s相连,t和汇点相连,权值都为无穷大。至此,就转换成最小割的模型,求出最大流即可。

手写isap写丑了,没有1A。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define min(x,y) (x)<(y)?(x):(y)
 4 const int N=1111,M=1e5+1111,INF=0x3f3f3f3f;
 5 struct node
 6 {
 7     int v,c,next;
 8 }e[M];
 9 int gap[N],h[N],head[N];
10 int s,t,n,m,cnt;
11 void init()
12 {
13     memset(head,-1,sizeof(head));
14     cnt=0;
15 }
16 void add(int u,int v,int w)
17 {
18     e[cnt].v=v,e[cnt].c=w;
19     e[cnt].next=head[u],head[u]=cnt++;
20     e[cnt].v=u,e[cnt].c=0;
21     e[cnt].next=head[v],head[v]=cnt++;
22 }
23 int dfs(int u,int flow)
24 {
25     if(u==t)    return flow;
26     int a,i,v,c=flow,minh=t;
27     for(i=head[u];i!=-1;i=e[i].next)
28     {
29         if(e[i].c)
30         {
31             v=e[i].v;
32             if(h[v]==h[u]-1)
33             {
34                 a=min(c,e[i].c);
35                 a=dfs(v,a);
36                 e[i].c-=a;
37                 e[i^1].c+=a;
38                 c-=a;
39                 if(h[s]>t)    return flow-c;
40                 if(!c)    break;
41             }
42             minh=min(minh,h[v]);
43         }
44     }
45     if(c==flow)
46     {
47         if(--gap[h[u]]==0)    h[s]=t+1;
48         ++gap[h[u]=minh+1];
49     }
50     return flow-c;
51 }
52 int isap()
53 {
54     memset(gap,0,sizeof(gap));
55     memset(h,0,sizeof(h));
56     int ans=0;gap[0]=t+1;
57     while(h[s]<=t)
58         ans+=dfs(s,INF);
59     return ans;
60 }
61 int main()
62 {
63     int T,u,v,i,ss,tt;
64     scanf("%d",&T);
65     while(T--)
66     {
67         scanf("%d%d%d%d",&n,&m,&ss,&tt);
68         init();s=0,t=2*n+1;
69         for(i=1;i<=n;i++)
70         {
71             int x;
72             scanf("%d",&x);
73             if(i!=ss&&i!=tt)
74                 add(i,i+n,x);
75             else
76                 add(i,i+n,INF);
77         }
78         while(m--)
79         {
80             scanf("%d%d",&u,&v);
81             add(u+n,v,INF);
82             add(v+n,u,INF);
83         }
84         add(s,ss,INF);add(tt+n,t,INF);
85         printf("%d\n",isap());
86     }
87     return 0;
88 }

时间: 2024-08-09 02:40:18

HDU 3491 最小点权割集的相关文章

hdu 1565&amp;hdu 1569(网络流--最小点权值覆盖)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7717    Accepted Submission(s): 2911 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数

HDU 1569 - 方格取数(2) - [最大点权独立集与最小点权覆盖集]

嗯,这是关于最大点权独立集与最小点权覆盖集的姿势,很简单对吧,然后开始看题. HDU1569: Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多个测试实例,

hdu 3657 最小割的活用 / 奇偶方格取数类经典题 /最小割

题意:方格取数,如果取了相邻的数,那么要付出一定代价.(代价为2*(X&Y))(开始用费用流,敲升级版3820,跪...) 建图:  对于相邻问题,经典方法:奇偶建立二分图.对于相邻两点连边2*(X&Y),源->X连边,Y->汇连边,权值w为点权. ans=总点权-最小割:如果割边是源->X,表示x不要选(是割边,必然价值在路径上最小),若割边是Y-汇点,同理:若割边是X->Y,则表示选Y点且选X点, 割为w( 2*(X&Y) ). 自己的确还没有理解其本质

hdu 4966 最小树形图

将每门课等级拆成0,1,2,3...a[i]个点,对每个等级大于0的点向它低一级连边,权值为0[意思是,若修了level k,则level(0~k)都当做修了] 将输入的边建边,权值为money[i]. 建立根节点,向每个level 0的点连边,权值为0[因为初始level 0的都修了] 由于题目要求每门课都必须达到最大level,也就是对应图中根节点能到达所有点,问题就变成了求无向图的最小生成树. #include<iostream> #include<cstdio> #incl

POJ2125 Destroying The Graph 最小点权覆盖

题目链接: poj2125 题意: 给出一张N个顶点M条边的有向图. 对于每个顶点x,有两种操作: 1,删除所有进入x的边,花费为a; 2.删除所有从x出去的边,花费为b. 问把图中所有边删除所需要的最小花费.并输出对应的操作. 解题思路: 由题目条件(删除入边,删除出边)首先想到应该是拆点. 这样题目的问题转化为最小点权覆盖问题.即用最少(花费)的顶点覆盖所有边 对于这个问题,我们可以用网络流中的最小割解决,方法如下: 源点连接拆后的出点,容量为b 汇点连接拆后的入点,容量为a 已有边容量为无

POJ 2125 --Destroying The Graph【最小割解决 &quot;最小点权覆盖问题&quot; &amp;&amp; 输出解(割边集) &amp;&amp; 各种不懂】

Destroying The Graph Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7597   Accepted: 2434   Special Judge Description Alice and Bob play the following game. First, Alice draws some directed graph with N vertices and M arcs. After that B

poj 3308 Paratroopers 最小割 最小点权覆盖

题目链接:http://poj.org/problem?id=3308 题意: 有一个M*N的图,上面的一些点上有伞兵. 可以设置一些枪在每行或者每列上,通过射击,这行或这列的伞兵就会被消灭.每个枪的设置有一个花费,如果设置多个枪,那么花费是设置每个枪的乘积. 问消灭所有伞兵最少的花费是多少. 思路: 每个点的伞兵至少要用那一列或者那一行设置的枪去消灭,那么就可以应用点覆盖的模型.把伞兵看成是一条边,这条边至少要用一个点来覆盖. 而题目中最终花费是所有花费的乘积,那么可以用对数log(x)+lo

HLG1407Leyni的游戏【最小点权覆盖集】

大意: 给你一个n行m列的矩阵 1 2 1 1 每次操作可使一整行或一整列的一个数减少1(如果是0则不变) 问最少多少次操作会使所有的数变为零 分析: 该题很像poj消灭外星人的那道题 思路也差不很多 将x轴当左集合,y轴当右集合,边权值为所在点的数字 那么一条边就代表了矩阵中的一个点 只要找出最小的权值去覆盖所有的边就能把所有的数字变为零 也就是传说中的最小点权覆盖集 最小点权覆盖集 = 最大权匹配 KM跑一遍就可以了 但是需要注意的是如果两边点的个数不相等 那么我们用虚拟点代替就可以了 代码

hdu 2255 二分图带权匹配 模板题

模板+注解在 http://blog.csdn.net/u011026968/article/details/38276945 hdu 2255 代码: //KM×î´ó×îСƥÅä #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; #define INF 0x0fffffff const int MAXN