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

大意:

给你一个n行m列的矩阵

1 2

1 1

每次操作可使一整行或一整列的一个数减少1(如果是0则不变)

问最少多少次操作会使所有的数变为零

分析:

该题很像poj消灭外星人的那道题

思路也差不很多

将x轴当左集合,y轴当右集合,边权值为所在点的数字

那么一条边就代表了矩阵中的一个点

只要找出最小的权值去覆盖所有的边就能把所有的数字变为零

也就是传说中的最小点权覆盖集

最小点权覆盖集 = 最大权匹配

KM跑一遍就可以了

但是需要注意的是如果两边点的个数不相等

那么我们用虚拟点代替就可以了

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5
 6 const int maxn = 205;
 7 const int INF = 1000000000;
 8 int n;
 9
10 int W[maxn][maxn];
11 int Lx[maxn], Ly[maxn];
12 int Left[maxn];
13 bool S[maxn], T[maxn];
14
15 bool match(int i) {
16     S[i] = true;
17     for(int j = 1; j <= n; j++) if(Lx[i] + Ly[j] == W[i][j] && !T[j]) {
18         T[j] = true;
19         if(!Left[j] || match(Left[j])) {
20             Left[j] = i;
21             return true;
22         }
23     }
24     return false;
25 }
26
27 void update() {
28     int a = INF;
29     for(int i = 1; i <= n; i++) if(S[i])
30         for(int j= 1; j <= n; j++) if(!T[j])
31             a = min(a, Lx[i] + Ly[j] - W[i][j]);
32     for(int i = 1; i <= n; i++) {
33         if(S[i]) Lx[i] -= a;
34         if(T[i]) Ly[i] += a;
35     }
36 }
37
38 void KM() {
39     for(int i = 1; i <= n; i++) {
40         Left[i] = Lx[i] = Ly[i] = 0;
41         for(int j = 1; j <= n; j++)
42             Lx[i] = max(Lx[i], W[i][j]);
43     }
44     for(int i = 1; i<= n; i++) {
45         for(;;) {
46             for(int j = 1; j <= n; j++) S[j] = T[j] = 0;
47             if(match(i)) break; else update();
48         }
49     }
50 }
51
52 int main() {
53     int num;
54     int m;
55     while(EOF != scanf("%d %d",&n, &m)) {
56         memset(W, 0, sizeof(W));
57         for(int i = 1; i <= n; i++) {
58             for(int j = 1; j <= m; j++) {
59                 scanf("%d",&num);
60                 W[i][j] = num;
61             }
62         }
63         n = max(n, m);
64         KM();
65         int ans = 0;
66         for(int i = 1; i <= n; i++) {
67             ans += Lx[i] + Ly[i];
68         }
69         printf("%d\n",ans);
70     }
71     return 0;
72 }

网络流代码:

  1 #include <iostream>
  2 #include <queue>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <vector>
  6 using namespace std;
  7
  8 const int maxn = 200 * 200 + 10;
  9 const int INF = 1000000000;
 10
 11 struct Edge {
 12     int from, to, cap, flow, cost;
 13 };
 14
 15 struct MCMF
 16 {
 17     int n, m, s, t;
 18     vector<Edge> edges;
 19     vector<int> G[maxn];
 20
 21     int inq[maxn];
 22     int d[maxn];
 23     int p[maxn];
 24     int a[maxn];
 25
 26     void init(int n) {
 27         this -> n = n;
 28         for(int i = 0; i < n; i++) G[i].clear();
 29         edges.clear();
 30     }
 31
 32     void AddEdge(int from, int to, int cap, int cost) {
 33         edges.push_back((Edge) { from, to, cap, 0, cost } );
 34         edges.push_back((Edge) { to, from, 0, 0, -cost } );
 35         m = edges.size();
 36         G[from].push_back(m - 2);
 37         G[to].push_back(m - 1);
 38     }
 39
 40     bool BellmanFord(int s, int t, int &flow, int &cost) {
 41         for(int i = 0; i < n; i++) d[i] = INF;
 42         memset(inq, 0, sizeof(inq) );
 43         d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;
 44         queue<int> Q;
 45         Q.push(s);
 46         while(!Q.empty()) {
 47             int u = Q.front(); Q.pop();
 48             inq[u] = 0;
 49             for(int i = 0; i < G[u].size(); i++) {
 50                 Edge &e = edges[G[u][i]];
 51                 if(e.cap > e.flow && d[e.to] > d[u] + e.cost) {
 52                     d[e.to] = d[u] + e.cost;
 53                     p[e.to] = G[u][i];
 54                     a[e.to] = min(a[u], e.cap - e.flow);
 55                     if(!inq[e.to]) { Q.push(e.to); inq[e.to] = 1; }
 56                 }
 57             }
 58         }
 59
 60         if(d[t] == INF) return false;
 61         flow += a[t];
 62         cost += d[t] * a[t];
 63         int u = t;
 64         while(u != s) {
 65             edges[p[u]].flow += a[t];
 66             edges[p[u] ^ 1].flow -= a[t];
 67             u = edges[p[u]].from;
 68         }
 69         return true;
 70     }
 71
 72     int MinCost(int s, int t) {
 73         //this -> s = s; this -> t = t;
 74         int flow = 0, cost = 0;
 75         while(BellmanFord(s, t, flow, cost)){};
 76         return cost;
 77     }
 78 };
 79
 80 MCMF g;
 81
 82 int main() {
 83     int n, m;
 84     int num;
 85     while(EOF != scanf("%d %d",&n, &m)) {
 86         int s = 0; int t = n + m + 1;
 87         g.init(n * m + 10);
 88         for(int i = 1; i <= n; i++) {
 89             for(int j = 1; j <= m; j++) {
 90                 scanf("%d",&num);
 91                 g.AddEdge(i, j + n, 1,-num);
 92             }
 93         }
 94         for(int i = 1; i <= n; i++) {
 95             g.AddEdge(s, i, 1, 0);
 96         }
 97         for(int j = 1; j <= m; j++) {
 98             g.AddEdge(j + m, t, 1, 0);
 99         }
100         printf("%d\n",-g.MinCost(s, t));
101     }
102     return 0;
103 }

TLE

HLG1407Leyni的游戏【最小点权覆盖集】,布布扣,bubuko.com

时间: 2024-10-06 12:43:55

HLG1407Leyni的游戏【最小点权覆盖集】的相关文章

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

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

POJ2125 Destroying The Graph (最小点权覆盖集)(网络流最小割)

Destroying The Graph Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8158   Accepted: 2620   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

【网络流专题4】 最小点权覆盖集

Ahead 11.1.2018 例题 poj 2125 题意为选取一些点使得覆盖所有的边 仍然是最小割与割点,对于每一条边的两个点,从源点向每个点连一条删除从这个点出发的所有边的权值 即W- ,同理对每一个点向汇点连W+ 中间部分为图的边关系. 然后最大流即可 针对方案需要进行一次深搜,对于与源点连接的点,如果不能被访问到,那么一定是割去的,对于与汇点相连的如果被访问到那么一定是割去的 代码 #include <iostream> #include <cstdlib> #inclu

poj 2125 Destroying The Graph 最小点权覆盖集+拆点+求割边

Destroying The Graph Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7570   Accepted: 2423   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 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

POJ3308 Paratroopers(最小割/最小点权覆盖)

把入侵者看作边,每一行每一列都是点,选取某一行某一列都有费用,这样问题就是选总权最小的点集覆盖所有边,就是最小点权覆盖. 此外,题目的总花费是所有费用的乘积,这时有个技巧,就是取对数,把乘法变为加法运算,最后再还原. 另外还可以从最小割的思路去这么理解: 每一行与源点相连,容量为该行的花费:每一列与汇点相连,容量为该列的花费:对于每个入侵者的坐标,该行该列连接一条容量INF的边. 要让源点汇点不连通,割边集必然与所有入侵者的行或列相关,而这样建模后的最小割就是最小的花费(容量INF的边必然不是最

二分图最小点权覆盖 二分图最大权独立集 方格取数 最小割

二分图最小点权覆盖: 每一条边 (u, v) 都是一个限制条件, 要求 u 和 v 不能同时取得. 我们考虑先取得所有的, 然后减去最小的点权. 建立原点 S , 连向二分图左边的所有点, 与 S 连通的意义是左边的点被选择了, 或者右边的点没有被选择. 建立汇点 T , 二分图右边的所有点连向它, 与 T 连通的意义是左边的点没有被选择, 或者右边的点被选择了. 利用最小割最大流定理, 我们跑最大流, 再根据最后一次 BFS 得出的情报构造方案. 定理 覆盖集与独立集互补. 证明 即证明覆盖集

【网络流】【最小点权覆盖】【NEERC 2003】【POJ2125】【cogs 1575】有向图破坏

1575. [NEERC 2003][POJ2125]有向图破坏 ★★★ 输入文件:destroyingthegraph.in 输出文件:destroyingthegraph.out 简单对比 时间限制:1 s 内存限制:256 MB [题目描述] Alice和Bob正在玩如下的游戏.首先Alice画一个有N个顶点,M条边的有向图.然后Bob试着摧毁它.在一次操作中他可以找到图中的一个点,并且删除它所有的入边或所有的出边. Alice给每个点定义了两个值:Wi+和Wi-.如果Bob删除了第i个点

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

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