您的位置:首页 > 其它

UVA 11419 SAM I AM

2015-08-02 10:43 323 查看

SAM I AM

Time Limit: 7000ms
Memory Limit: 131072KB
This problem will be judged on UVA. Original ID: 11419
64-bit integer IO format: %lld Java class name: Main

The world is in great danger!! Mental's forces have returned to Earth to eradicate humankind. Our last hope to stop this great evil is Sam Serious Stone. Equipped with various powerful weapons, Serious Sam starts his mission to destroy the forces of evil.

After fighting two days and three nights, Sam is now in front of the temple KOPTOS where Mental's general Ugh Zan III is waiting for him. But this time, he has a serious problem. He is in shortage of ammo and a lot of enemies crawling inside the temple waiting for him. After rounding the temple Sam finds that the temple is in rectangle shape and he has the locations of all enemies in the temple.

All of a sudden he realizes that he can kill the enemies without entering the temple using the great cannon ball which spits out a gigantic ball bigger than him killing anything it runs into and keeps on rolling until it finally explodes. But the cannonball can only shoot horizontally or vertically and all the enemies along the path of that cannon ball will be killed.

Now he wants to save as many cannon balls as possible for fighting with Mental. So, he wants to know the minimum number of cannon balls and the positions from which he can shoot the cannonballs to eliminate all enemies from outside that temple.

Input

Here, the temple is defined as a RXC grid. The first line of each test case contains 3 integers: R(0<R<1001), C(0<C<1001) representing the grid of temple (R means number of row and C means number of column of the grid) and the number of enemies N(0<N<1000001) inside the temple. After that there are N lines each of which contains 2 integers representing the position of the enemies in that temple. Each test case is followed by a new line (except the last one). Input is terminated when R=C=N=0. The size of the input file is around 1.3 MB.

Output

For each test case there will be one line output. First print the minimum number (m) of cannonballs needed to wipe out the enemies followed by a single space and then m positions from which he can shoot those cannonballs. For shooting horizontally print r followed by the row number and for vertical shooting print c followed by the column number. If there is more than one solution any one will do.

Sample Input

4 4 3

1 1

1 4

3 2

4 4 2

1 1

2 2

0 0 0

Output for Sample Input

2 r1 r3

2 r1 r2

解题:最小点覆盖,最小点覆盖等于最大匹配数,关键在于如何把点覆盖中的点输出出来

来自Matrix67大神的解说

二分图最大匹配的König定理及其证明
本文将是这一系列里最短的一篇,因为我只打算把König定理证了,其它的废话一概没有。
以下五个问题我可能会在以后的文章里说,如果你现在很想知道的话,网上去找找答案:
1. 什么是二分图;
2. 什么是二分图的匹配;
3. 什么是匈牙利算法;(http://www.matrix67.com/blog/article.asp?id=41)
4. König定理证到了有什么用;
5. 为什么o上面有两个点。

König定理是一个二分图中很重要的定理,它的意思是,一个二分图中的最大匹配数等于这个图中的最小点覆盖数。如果你还不知道什么是最小点覆盖,我也在这里说一下:假如选了一个点就相当于覆盖了以它为端点的所有边,你需要选择最少的点来覆盖所有的边。比如,下面这个图中的最大匹配和最小点覆盖已分别用蓝色和红色标注。它们都等于3。这个定理相信大多数人都知道,但是网络上给出的证明并不多见。有一些网上常见的“证明”明显是错误的。因此,我在这里写一下这个定理的证明,希望对大家有所帮助。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1005;
vector<int>g[maxn];
bool T[maxn],S[maxn];
int Link[maxn],n,m,k,Link2[maxn];
bool match(int u) {
S[u] = true;
for(int i = g[u].size()-1; i >= 0; --i) {
if(!T[g[u][i]]) {
T[g[u][i]] = true;
if(Link[g[u][i]] == -1 || match(Link[g[u][i]])) {
Link[g[u][i]] = u;
Link2[u] = g[u][i];
return true;
}
}
}
return false;
}
int main() {
int u,v;
vector<int>X,Y;
while(scanf("%d%d%d",&n,&m,&k),n||m||k) {
for(int i = 0; i < maxn; ++i) g[i].clear();
for(int i = 0; i < k; ++i) {
scanf("%d%d",&u,&v);
g[u].push_back(v);
}
int ret = 0;
memset(Link,-1,sizeof Link);
memset(Link2,-1,sizeof Link2);
for(int i = 1; i <= n; ++i) {
memset(S,false,sizeof S);
memset(T,false,sizeof T);
if(match(i)) ++ret;
}
X.clear();
Y.clear();
memset(S,false,sizeof S);
memset(T,false,sizeof T);
for(int i = 1; i <= n; ++i)
if(Link2[i] == -1) match(i);
for(int i = 1; i <= n; ++i)
if(!S[i]) X.push_back(i);
for(int j = 1; j <= m; ++j)
if(T[j]) Y.push_back(j);
printf("%d",ret);
for(int i = 0; i < X.size(); ++i)
printf(" r%d",X[i]);
for(int j = 0; j < Y.size(); ++j)
printf(" c%d",Y[j]);
putchar('\n');
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: