Uva - 11419 - SAM I AM

题意:一个矩形——R*C的网格,在某些位置上有石头,在网格外开一炮可以打掉该行或者该列的石头,求打掉这些石头最少需要多少门大炮,位置分别设在哪行哪列(0<R<1001, 0 < C < 1001)。

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2414

——>>以每行为X结点,每列为Y结点,有石头的点的横纵坐标关系为边建立二分图,那么,对于一个石头的位置,就是一条边,只要在这条边2个端点中的1个设大炮就可打掉这个石头,这正正是二分图的最小点覆盖。

对于具体的位置,则可从X中所有的未盖点出发,寻找增广路,并且标记沿途经过的结点,那么X中未被标记的点和Y中被标记的点即为所求,这是因为:

从X中的未盖点出发,终点一定在X结点(否则存在增广路,与最大匹配矛盾),那么这次增广中标记Y结点的数量就会比标记X结点的数量少1,故取已标记的Y结点用的大炮就会比取已标记的X结点的数量要少1。

对于X中未被标记的结点a,首先a是已盖点,Y中必有结点b与之匹配,且b一定不和X中的未盖点相连(否则a,b一定被标记了),若a还与Y中的未盖点相连,则应取a,而不是b及与a相连的Y中的未盖点,这样只在a一个点设大炮就可解决掉这几个石头;若a连的还有Y中的已盖点,那么那点由它的匹配点去处理,a不用去处理它;若a不与Y的其它点相连,那么取a点或者取b都行,我取了a点,所以这些情况取已盖点a就是。

综上可得取X中未被标记的点和Y中被标记的点就是设大炮的行与列。

另外,用邻接表会比用简单的邻接矩阵快10倍!Uva - 11419 - SAM I AM

#include <cstdio>
#include <cstring>
#include <algorithm> using namespace std; const int maxn = 1000 + 10;
const int maxm = 1000000 + 10; int R, C, fa[maxn], mo[maxn], v[maxm], head[maxn], nxt[maxm], ecnt;
bool S[maxn], T[maxn]; void init(){
memset(head, -1, sizeof(head));
ecnt = 0;
} void addEdge(int uu, int vv){
v[ecnt] = vv;
nxt[ecnt] = head[uu];
head[uu] = ecnt;
ecnt++;
} bool match(int i){
S[i] = 1;
for(int e = head[i]; e != -1; e = nxt[e]) if(!T[v[e]]){
T[v[e]] = 1;
if(!fa[v[e]] || match(fa[v[e]])){
fa[v[e]] = i;
return 1;
}
}
return 0;
} void solve(){
memset(fa, 0, sizeof(fa));
int ret = 0;
for(int i = 1; i <= R; i++){
memset(S, 0, sizeof(S));
memset(T, 0, sizeof(T));
if(match(i)) ret++;
}
memset(mo, 0, sizeof(mo));
memset(S, 0, sizeof(S));
memset(T, 0, sizeof(T));
for(int i = 1; i <= C; i++) mo[fa[i]] = 1;
for(int i = 1; i <= R; i++) if(!mo[i]) match(i);
printf("%d", ret);
for(int i = 1; i <= R; i++) if(!S[i]) printf(" r%d", i);
for(int i = 1; i <= C; i++) if(T[i]) printf(" c%d", i);
puts("");
} int main()
{
int N, x, y;
while(scanf("%d%d%d", &R, &C, &N) == 3){
if(!R && !C && !N) return 0;
init();
for(int i = 1; i <= N; i++){
scanf("%d%d", &x, &y);
addEdge(x, y);
}
solve();
}
return 0;
}
上一篇:SQL实现如何计算项目进度总共天数情况、已经施工天数情况、以及施工进度百分比


下一篇:springboot秒杀课程学习整理1-4