清洁机器人

//何老板翻译

问题描述

何老板的公司生产了一种机器人,可以用于在运动会后清理运动场上的垃圾。在机器人开始工作前,给出了一张网格状的地图,每个包含垃圾的格子都被标记上了“G”。所有的机器人一开始都位于西北方的那一角,在工作结束时所有的机器人都会走到东南方的那一角。每个机器人只能往东和往南两个方向行走。一走到有垃圾的格子,机器人就会把垃圾清理掉。一旦机器人走到了东南方那一个角,它就会自动切断电源,不能再次工作。
你的任务是计算出最少需要多少个机器人,就能清理完所有的垃圾。
例如下图:所有的机器人一开始在(1,1)位置,结束时在(6,7)位置
清洁机器人_第1张图片
下图展示了两种可能的方案,其中第二种方案更好,因为它只用了两个机器人。
清洁机器人_第2张图片

输入格式

由一行或多行构成,每行两个空格间隔的整数,表示一个包含垃圾的格子坐标
输入由0 0 作为结束。
注:每组测试数据的格子坐标是按行由小到大的顺序给出。
地图的行数和列数都不超过24

输出格式

若干行,每行一个整数,表示对应测试数据的结果。

样例输入

1 2
1 4
2 4
2 6
4 4
4 7
6 6
0 0

样例输出

2


题解

思路1:DP

此问题可转化为求“最长上升子序列”。
显然,假如其中的一些垃圾从左下往右上排列,其中任何两格垃圾都不能用一个机器人收集。所以,所需机器人数即为最长的这样的序列的长度(显然,其它垃圾都可以用清理这些格子的机器人清理,否则序列还可加长)。
推出方程,可用前缀和优化。

思路2:二分图

开始我们假设每个格子都需要一个机器人。
显然,如果一个机器人能从i 号垃圾走到j 号垃圾,那么j 号的机器人可以不用。
并且,每个机器人清理完某个垃圾后,接下来只能去另一格,每个垃圾又只能由一个机器人清理。这就转化为了二分图模型(如果i 号垃圾可到达j 号垃圾,则从 i 向 j’连边)。
但这种方法在时空效率上显然没有DP优秀。。。


代码

1、DP
#include 
#include 
using namespace std;
int f[29][29],a[29][29];
int main()
{
    int i,j;
    while(true)
    {
        scanf("%d%d",&i,&j);
        if((!i)&&(!j))break;
        a[i][j]=1;
    }
    for(i=24;i;--i)
        for(j=1;j<=24;j++)
            f[i][j]=max(f[i+1][j],max(f[i][j-1],a[i][j]+f[i+1][j-1]));
    printf("%d",f[1][24]);
    return 0;
}
2、二分图
#include 
#include 
using namespace std;
const int Q=1e3;
int link[Q],ch[Q],e[Q*Q],nn[Q*Q],last[Q],x[Q],y[Q],tot=0;
bool search(int x,int k)
{
    for(int t=last[x];t;t=nn[t])
    {
        int y=e[t];
        if(ch[y]==k)continue;
        ch[y]=k;
        if((!link[y])||search(link[y],k)){
            link[y]=x;return true;
        }
    }
    return false;
}
void add(int x,int y)
{
    e[++tot]=y;
    nn[tot]=last[x];
    last[x]=tot;
}
int main()
{
    int i,j,n=0,ans=0;
    while(true){
        scanf("%d%d",&x[n+1],&y[n+1]);
        if((!x[n+1])&&(!y[n+1]))break;
        ++n;
    }
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            if(i!=j&&x[i]<=x[j]&&y[i]<=y[j])
                add(i,j);
    for(i=1;i<=n;i++)
        if(search(i,i))ans++;
    printf("%d",n-ans);
    return 0;
}

你可能感兴趣的:(清洁机器人)