uva 11419 SAM I AM 求出二分图的最小点覆盖集

本文深入探讨了游戏开发领域的关键技术,包括游戏引擎、编程语言、硬件优化等,同时着重介绍了AI音视频处理的应用场景和实现方法,如语义识别、语音变声等,为开发者提供全面的技术指南。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem C
SAM I AM
Input: 
Standard Input

Output: Standard Output

 

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 thetemple Sam finds that the temple is in rectangle shape and he has the locations of all enemies in the temple.

C:\Documents and Settings\Angel of Death\Desktop\sam grid.gifAll 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                               Output for Sample Input

4 4 3

1 1

1 4

3 2

 

4 4 2

1 1

2 2

 

0 0 0

 

2 r1 r3

2 r1 r2

 


Problemsetter: Syed Monowar Hossain

Special Thanks: Derek Kisman


题意:给你一幅网格图,每个网格可能放置一个物品,可以在网格外发射子弹,子弹会沿着垂直或者水平方向飞行,并且打掉飞行路径上的所有目标,你的任务是计算出需要的最少的子弹,各从那些位置发射,才能把所有的目标全部打掉。


分析:我们可以建立一个二分图,左边的X表示行,右边的Y表示列,则每个物品对应一个X—Y,则问题转化为了求二分图的最小点覆盖,即最大匹配数。对于怎么求出最小点覆盖的集合,题目要求如果有多组答案,随便输出一组即可,所以我们可以这样做:当求完最大匹配的时候,我们从左边X集合中没有被匹配到的点出发,进行DFS生成匈牙利树,对于每个被遍历到的点,对其进行标记,之后,左边X集合中未标记的点和右边Y集合中已经标记的点,组成了最小点覆盖集。


简单说明:为什么这样做选出的点数就是最大匹配的点数呢?因为我们每次从X集合中的点出发的都是没有被匹配过的点,Y集合中的点都是已经匹配了的点,我们从X出发走到Y,Y也覆盖了这些没有被匹配的边,而在寻找增广路径的过程中,标记了左边X集合中已经匹配过的部分点,因此X集合中剩下的没有标记的点也要加入答案中,这些没有被标记的点,连接的一定是剩下的已经匹配了的边。


代码:

#pragma comment(linker,"/STACK:102400000,102400000")
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <string>
#include <math.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
typedef long long ll;   //记得必要的时候改成无符号
const int maxn=2005;   //点数
const int maxm=1000005;   //边数
struct EdgeNode
{
    int to;
    int next;
}edge[maxm];
int head[maxn],cnt;
void add(int x,int y)
{
    edge[cnt].to=y;edge[cnt].next=head[x];head[x]=cnt++;
}

int n,m,v[maxn],pre[maxn],vx[maxn],vy[maxn],pip[maxn];

void init()
{
    cnt=1;
    memset(head,-1,sizeof(head));
}

bool dfs(int x)
{
    int y;
    vx[x]=1;          //用来求最小点覆盖的点
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        y=edge[i].to;
        if(!v[y])
        {
            v[y]=1;
            vy[y]=1;     //用来求最小点覆盖的点
            if(!pre[y]||dfs(pre[y]))
            {
                pre[y]=x;
                pip[x]=1;
                return true;
            }
        }
    }
    return false;
}

int erfenpipei()     //也求出了最小点覆盖的点
{
    int sum=0;
    memset(pre,0,sizeof(pre));
    memset(pip,0,sizeof(pip));
    for(int i=1;i<=n;i++)
    {
        memset(v,0,sizeof(v));
        if(dfs(i))
            sum++;
    }
    memset(vx,0,sizeof(vx));
    memset(vy,0,sizeof(vy));
    for(int i=1;i<=n;i++)
    {
        memset(v,0,sizeof(v));
        if(!pip[i])
            dfs(i);
    }
    return sum;
}

int main()
{
    int k,i,x,y;
    while(~scanf("%d%d%d",&n,&m,&k)&&(n+m+k))
    {
        init();
        for(i=1;i<=k;i++){
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        printf("%d",erfenpipei());
        for(i=1;i<=n;i++)if(!vx[i])printf(" r%d",i);
        for(i=1;i<=m;i++)if(vy[i])printf(" c%d",i);
        printf("\n");
    }
    return 0;
}



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值