ZR#954 分组

ZR#954 分组

解法:

设 $ f[i][a][b] $ 表示考虑了排序后的前 $ i $ 个人,目前已经有 $ a $ 个组配好了,还有 $ b $ 个组只有组员没有组长的最小代价。转移时,考虑当前的人是作为组长,加入一个已经有组员的组,还是作为组员新建一个组即可。
然后对于有的人重要程度相同的情况,我们需要想办法继续保证组长在组员的后面。则对于重要程度相同的两个人,我们按照他们的志愿排序:先是只能当组员的,然后是都可以的,然后是只能当组长的。
时间复杂度:$ O(nk^2) $ ,可以通过前 3 个子任务。
然后因为如果 $ k imes 2 > n $ ,一定无解,所以特判一下就好了。

CODE:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

#define LL long long
#define N 1001000
#define INF 0x3f3f3f3f3f3f3f3fll

LL n,k,f[2][1010][1010];
struct Neo {
    LL w,s,p;
}a[N];

inline bool cmp(Neo x,Neo y) {
    if(x.w != y.w) 
        return x.w < y.w;
    return x.p < y.p;
}

int main() {
    scanf("%lld%lld",&n,&k);
    for(int i = 1 ; i <= n ; i++) {
		scanf("%lld%lld%lld",&a[i].w,&a[i].s,&a[i].p);
		if(a[i].p == 1) a[i].p = 3;
		else if(a[i].p == 2) a[i].p = 1;
		else if(a[i].p == 3) a[i].p = 2;
	}
    if(2 * k > n) {
        puts("-1");
        return 0;
        //system("pause");
    }
    sort(a+1,a+n+1,cmp);
    memset(f,0x3f,sizeof(f));
    f[0][0][0] = 0;
    int now = 1,las = 0;
    for(int i = 1 ; i <= n ; i++) {
	    for(int j = 0 ; j <= k ; j++) {
		    for(int l = 0 ; j + l <= k ; l++) {
			    f[now][j][l] = f[las][j][l];
			    if(a[i].p < 3) {
		    		if(l >= 1) f[now][j][l] = min(f[now][j][l],f[las][j][l - 1] + a[i].s);
		    	}
			    if(a[i].p > 1) { 
			    	if(j >= 1) f[now][j][l] = min(f[now][j][l],f[las][j - 1][l + 1]+a[i].s);
			    }
		    }
	    }
		swap(now,las);
	}
    if(f[las][k][0] >= INF) {
        puts("-1");
        return 0;
    }
    printf("%lld 
",f[las][k][0]);
    //system("pause");
    return 0;
}
原文地址:https://www.cnblogs.com/Repulser/p/11448937.html