HDU 4293 Groups 区间覆盖 区间DP

本文探讨了一组ACM者沿长街行走并提供关于他们组前后人数的信息场景,分析如何在给定错误信息的情况下,最大化确定正确信息的数量。通过输入玩家数量、在他们组之前和之后的人数,输出最优情况下正确信息的数量。

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

题目描述:

Description
  After the regional contest, all the ACMers are walking alone a very long avenue to the dining hall in groups. Groups can vary in size for kinds of reasons, which means, several players could walk together, forming a group.
  As the leader of the volunteers, you want to know where each player is. So you call every player on the road, and get the reply like “Well, there are A i players in front of our group, as well as B i players are following us.” from the i th player.
  You may assume that only N players walk in their way, and you get N information, one from each player.
  When you collected all the information, you found that you’re provided with wrong information. You would like to figure out, in the best situation, the number of people who provide correct information. By saying “the best situation” we mean as many people as possible are providing correct information.

Input
  There’re several test cases.
  In each test case, the first line contains a single integer N (1 <= N <= 500) denoting the number of players along the avenue. The following N lines specify the players. Each of them contains two integers A i and B i (0 <= A i,B i < N) separated by single spaces.
  Please process until EOF (End Of File).

Output
  For each test case your program should output a single integer M, the maximum number of players providing correct information.

Sample Input

3
2 0
0 2
2 2
3
2 0
0 2
2 2 

Sample Output

2
2 

Hint
The third player must be making a mistake, since only 3 plays exist.

题目分析:

有n个人,分成若干组,他们都会提供一个信息,在他们组(不是他)之前有多少人,之后有多少人。然而,有些人说的是谎话,你需要判断,在尽可能让多的人说真话的前提下,求出说真话的人数。
简化一下题目,就是在0~n的区间中,你通过在该区间前后长度来确定区间,同时这个区间可以取多次,(对应题目的数个人在同一组)当然这个取这个区间的次数必须是区间长度范围内,(对应一个区间的人数不能超过该区间的最大能容下的人数)。然后就贪心计算不会重复覆盖的区间个数,就是本题答案。

还有DP的做法。

代码如下:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

const int MAXN =510;
using namespace std;


struct node
{
    int l,r;
    int num;
}pp[MAXN];

bool cmp(node a,node b)
{
    if (a.l==b.l) return a.r<b.r;
    else return a.l<b.l;
}

int n;
int main()
{
    while(scanf("%d",&n)!=-1)
    {
        int nn=0;
        for(int i=1; i<=n; i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            if (a+b>=n) continue;//不合法情况,即区间左端点比右端点大的情况
            pp[nn].l=a+1;
            pp[nn].r=n-b;
            pp[nn].num=1;
            nn++;
        }
        sort(pp,pp+nn,cmp);
        if (nn==0) {printf("0\n");continue;}
        int group=0;//初始第一个人在一组
        for(int i=1; i<nn; i++)
        {
            if (pp[i].l==pp[group].l && pp[i].r==pp[group].r)
            {
                pp[group].num++;//在同一组
                pp[group].num=min(pp[group].num,pp[group].r-pp[group].l+1);//在同一组的人数不能比这区间人数更多了
            }
            else
            {
                group++;//新的一组,将group值更新
                pp[group].l=pp[i].l;
                pp[group].r=pp[i].r;
                pp[group].num=pp[group].num;
            }
        }
        int ans=pp[0].num;
        for(int i=1; i<=group; i++)
        {
            int t=0;
            for(int j=0; j<i; j++)
            {
                if (pp[j].r<pp[i].l && pp[j].num>t) t=pp[j].num;
                //前一个条件判断合法性 后一个条件判断是否值得更新
            }
            pp[i].num+=t;//前i组可以取得的最大区间数量
            ans=max(ans,pp[i].num);
        }
        printf("%d\n",ans);
    }
    return 0;
}

这种做法就类似与HDU2037

DP做法:

#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;

int dp[510][510];    
int tt[510][510], an[510];

int main()
{
    int i, j, k;
    int n, a, b;
    while(scanf("%d", &n) != EOF)
    {
        memset(dp, 0, sizeof(dp));
        memset(an, 0, sizeof(an));
        memset(tt, 0, sizeof(tt));

        for(i = 0; i < n; ++i) {
            scanf("%d %d", &a, &b);
            if(a+b < n && tt[a][n-b] < (n-a-b))
                tt[a][n-b]++;
        }

        for(i = 1; i <= n; ++i)
        for(j = 0; j < i; ++j) {
            dp[j][i] = an[j]+tt[j][i];
            an[i] = max(an[i], dp[j][i]);
        }

        printf("%d\n", an[n]);
    }
    return 0;
}

用dp[ i ][ j ] 表示从第 i+1 个人到第 j 个人为一组的时候前j个人中说真话最多的人

用tt[ i ][ j ] 表示从第 i 个人到第 j 个人之间站了多少人

用an[ i ]表示到第 i 个人前面说真话的人最多人数

tt[ a ][ b ]的人数不应该多于 n-(b-a+1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值