UPC H: Team 并查集和DP

 

输入 n,m

给 3*n个人的能力值,和m 对 关系,

有关系的人必须组成一队,,(一队只能3人)

2 1
1 2 3 4 5 6
3 4

整理后的结果是    

单人的  1 2 5 6   两人一组的是  (3,4)  要想组成一队,就是 1,2,5   (3,4,6)  这是一种组法

组成队伍后的能力值是最小的那个人的能力值,所有队伍能力值最大是多少?

 

大佬思路: 并查集处理原始数据,变成 单人双人小组分开

组成队伍的情况只有两种,1,三个单人 。2,一单一双

然后DP。(这四个字让我眼前一黑)

 

dp[i][j]  表示 用了 i 个单人 ,j个双人 小组来   组成的 队伍 的 能力最大值

dp[i][j]  需要考虑的是,能否组成队伍,怎么组成队伍(最弱的人分给哪两个倒霉蛋)

状态转移方程:(不知道写的对不对)

dp[i][j]=max(dp[i-3][j] + 单【i】, dp[i-1][j-1] + min(单【i】,双【j】)  )

i,j 状态需要前面的状态推出来,那就从前向后递推,dp[0][0] = 0

如果 dp【i】【j】能组成队伍  dp【i+3】【j】 和 dp【i+1】【j+1】就都能组成队伍

dp【i+3】【j】=max(dp【i+3】【j】,dp【i】【j】+a【i】);

dp[i+1][j+1]=max(dp[i+1][j+1],dp[i][j]+min(a[i],b[j]  )  )


#include
using namespace std;
typedef long long ll;
ll dp[3100][3100];
int f[3003];
ll dui[3003];
int sum[3003];
ll v[3003];
vectorq1;
vectorq2;
vectorq3;
bool flag=0;

int findd(int a)
{
    if(f[a]==a)
        return a;
    else
        return f[a]=findd(f[a]);
}

void marge(int a,int b)
{
    int fa=findd(a);
    int fb=findd(b);
    if(fa!=fb){
//        if(fa3)
                flag=1;

            sum[fb]=0;
            v[fa]=min(v[fa],v[fb]);//  第fa 支队伍的能力值,,,其实直接用 dui【】 这个数组就行
//
//        }
//        else
//        {
//            f[fa]=fb;
//            sum[fb]+=sum[fa];
//            if(sum[fb]>3)
//                flag=1;
//            sum[fa]=0;
//            v[fb]=min(v[fa],v[fb]);
//        }
    }
}
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<3*n;i++)
    {
        cin>>dui[i];  //第i人的能力 
        f[i]=i;       //第i人属于哪个队伍
        sum[i]=1;     //第i人所在队伍人数
        v[i]=dui[i];  //第i人的能力
    }

    for(int i=0;i>a>>b;
        marge(a-1,b-1);
    }

    if(flag==1){
        cout<<-1<

问题:不会发生   一个人同时加入了,由三个单人组成的队伍和 一个单人,一个两人小组的队伍

不会的,因为你已经排序了

最优解的计算方式只有一种:

UPC H: Team 并查集和DP_第1张图片

着急开班会,字迹潦草,多多包涵。

这个题,我觉得还不是特别理解,,希望有人和我讨论讨论。

自己太菜了没办法呀,自己想绝对想不到

偷偷放上超哥 的代码  应该不会被发现的,,,哈哈哈

//
//#include
//#include
//#include
//using namespace std;
//const int maxn = 3e3+5;
//int n,m;
//int a[maxn],b[maxn],fa[maxn],ta,tb;
//long long ans=0,dp[maxn][maxn];
//
//int Find(int x) {
//    return fa[x]==-1?x:fa[x]=Find(fa[x]);
//}
//void Union(int x,int y) {
//    x=Find(x); y=Find(y);
//    if (x!=y) {
//        fa[y]=x;
//        a[x]=min(a[x],a[y]);
//        b[x]+=b[y];
//        b[y]=0;
//    }
//}
//int main()
//{
//    memset(fa,-1,sizeof fa);
//    scanf("%d%d",&n,&m);
//    for (int i=1;i<=n*3;i++) {
//        scanf("%d",&a[i]); b[i]=1;
//    }
//    for (int i=1;i<=m;i++) {
//        int x,y;
//        scanf("%d%d",&x,&y);
//        Union(x,y);
//    }
//    for (int i=1;i<=n*3;i++) {
//        if (b[i]==1) a[ta++]=a[i];
//        if (b[i]==2) b[tb++]=a[i];
//        if (b[i]==3) ans+=a[i];
//        if (b[i]>=4) return 0*puts("-1");
//    }
//    sort(a,a+ta);
//    sort(b,b+tb);
//
//    memset(dp,-1,sizeof dp);
//    dp[0][0]=0;
//    for (int i=0;i

 

你可能感兴趣的:(#,dp)