UVA 11419 SAM I AM
2017-10-17 13:56
344 查看
UVA 11419 SAM I AM
二分图最小点覆盖,输出方案题目
给出一个R×C的网格,网格上棉纺了一些目标。可以在网格外发射子弹,子弹会沿着垂直或水平方向飞行,并且打掉飞行路径上的所有目标。你的任务是计算出最少需要多少子弹,各从哪个位置发射,才能把所有目标全部打掉。思路
二分图最大匹配的König定理及其证明König定理:最小覆盖数等于最大匹配数。把目标所在的坐标,转化为XY结点,行看成X结点,列看成Y结点。那现在问题就变成了,如何选最少的结点,覆盖所有的边。
求最小覆盖的步骤大致如下:1)在右边找到一个未被匹配过的点,标记。2)走一条没被匹配过的边,到左边的点,标记。3)走一条匹配过的边到右边,标记。4)重复2,3步骤直到不能再走。5)回到步骤一,直到找不到未被匹配且未被标记的右边的点。6)标记结束后,右边没有标记的点,和左边标记过的点,就可以覆盖所有的边。
左边右边是等价的,根据自己习惯命名就好
代码
#include<bits/stdc++.h> #include<stdlib.h> #define M(a,b) memset(a,b,sizeof(a)) #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 using namespace std; const int MAXN=1007; const int oo=0x3f3f3f3f; typedef long long LL; struct BPM { int n, m; vector<int > G[MAXN]; int left[MAXN]; int right[MAXN]; bool T[MAXN]; bool S[MAXN]; void init(int n,int m) { this->n = n; this->m = m; for(int i = 1; i <= n; i++) G[i].clear(); } void addEdge(int u, int v) { G[u].push_back(v); //建边 } bool match(int u) { S[u] = true; //标记右边的点u for(int i = 0; i < G[u].size(); i++) //遍历由u点出发,连接的左边的点 { int v = G[u][i]; if(!T[v]) //左边的没标记过的点, 走没匹配过的边 { T[v] = true; if(left[v] == -1 || match(left[v])) //走匹配过的边到右边的点 { left[v] = u; right[u] = v; return true; } } } return false; } int solve() { memset(left, -1, sizeof(left)); memset(right, -1, sizeof(right)); int ans = 0; for(int u = 1; u <= n; u++) { memset(S, 0, sizeof(S)); memset(T, 0, sizeof(T)); if(match(u)) ans++; //先用匈牙利算法求出最大匹配 } return ans; } int mincover(vector<int>& X, vector<int>& Y)//求解最小覆盖方案 { int ans = solve(); memset(S, 0, sizeof(S)); memset(T, 0, sizeof(T)); for(int u = 1; u <= n; u++) //在右边的点集找到一个未被标记的点 if(right[u] == -1) match(u); //从这个未标记的点开始走增广路 for(int u = 1; u <= n; u++) if(!S[u]) X.push_back(u); //标记结束之后,记录右边没标记的点 for(int v = 1; v <= m; v++) if( T[v]) Y.push_back(v); //记录左边标记过的点 return ans; } } bpm; int main() { int n,m,k; while(scanf("%d%d%d",&n,&m,&k)==3) { if(n==0&&m==0&&k==0) break; bpm.init(n,m); while(k--) { int a,b; scanf("%d%d",&a,&b); bpm.addEdge(a,b); } vector<int> X,Y; X.clear(),Y.clear(); int res=bpm.mincover(X,Y); printf("%d",res); for(int u:X) { printf(" r%d",u); } for(int v:Y) { printf(" c%d",v); } printf("\n"); } return 0; }
相关文章推荐
- uva 11419 - SAM I AM(最小覆盖)
- UVA 11419 SAM I AM (最小点覆盖,匈牙利算法)
- Uva-11419-SAM I AM
- UVA - 11419 SAM I AM
- Uva - 11419 - SAM I AM(二分图最小点覆盖)
- UVa 11419 SAM I AM (最小覆盖数)
- UVA - 11419 SAM I AM
- Uva - 11419 - SAM I AM
- UVA 11419 SAM I AM(二分图最小覆盖+答案输出)
- SAM I AM UVA - 11419 最小点集覆盖 要输出具体覆盖的行和列。
- UVA 11419 SAM I AM 二分图+最小覆盖点
- uva11419 SAM I AM(最小顶点覆盖+输出顶点)
- uva 11419 SAM I AM 求出二分图的最小点覆盖集
- UVA 11419 SAM I AM
- UVALive 11419 SAM I AM (最小点覆盖输出)
- UVA 11419 - SAM I AM(二分图匹配+最小点覆盖)
- Uva 11419 SAM I AM
- UVa:11419 SAM I AM
- UVA11419[SAM I AM] 二分图最小覆盖模型
- uva11419——SAM I AM——————【最小覆盖数、打印最小覆盖】