当前位置:编程学习 > C/C++ >>

HDU 4293 Groups(12年成都网络赛-DP)

题目链接:Click here~~
题意:
有 n 个人,可任意分成若干组,然后每个人各提供一个信息,表示他们组前面有多少个人,后面有多少个人。问最多有多少个信息是不冲突的。
解题思路:
可以把 n 个人看成一段区间 [1,n]。
设每个人的信息是a、b,则这个信息代表了他们组所在的区间 S 为 [a+1,n-b]。
若某些人是一组的,当且仅当他们信息所代表的区间是相同的。
当你相信其中某一个人说的话的时候,你必定会相信另一个人所说的相同的话,于是我们可以将这些相同的区间合并到一起,记录一下值。
问题转化成了在 [1,n] 这段区间中分布的若干个带有权值的区间,问如何选取一些不相交的区间,使权值之和最大。

我的做法是先按照区间的右端点进行排序,然后设 dp[ i ] 表示选取第 i 个区间时,区间 [1,S[ i ].b] 能取到的最大权值和。
则 dp[ i ] = num[ i ] + max{ dp[ j ] } (j < i 且 S[ j ].b < S[ i ].a)。

最后找到最大的 dp[ i ] 即为解。
[cpp]
#include <stdio.h> 
#include <string.h> 
#include <algorithm> 
using namespace std; 
 
#define N 505 
 
struct Int 

    int a,b; 
    Int(){} 
    Int(int _a,int _b):a(_a),b(_b){} 
    bool operator < (const Int& s)const 
    { 
        return b < s.b || b == s.b && a < s.a; 
    } 
}S[N]; 
 
int num[N][N],dp[N]; 
 
int main() 

    int n,a,b; 
    while(~scanf("%d",&n)) 
    { 
        int m = 0; 
        memset(num,0,sizeof(num)); 
        memset(dp,0,sizeof(dp)); 
        for(int i=0;i<n;i++) 
        { 
            scanf("%d%d",&a,&b); 
            if(a+b > n-1 || num[a+1][n-b] == n-b-a) 
                continue; 
            if(!num[a+1][n-b]) 
                S[m++] = Int(a+1,n-b); 
            ++num[a+1][n-b]; 
        } 
        sort(S,S+m); 
        int ans = 0; 
        for(int i=0;i<m;i++) 
        { 
            int mmax = 0; 
            for(int j=0;j<i;j++) 
                if(S[j].b < S[i].a) 
                    mmax = max(mmax,dp[j]); 
            dp[i] = mmax + num[S[i].a][S[i].b]; 
            ans = max(ans,dp[i]); 
        } 
        printf("%d\n",ans); 
    } 
    return 0; 

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,