[ZROJ-954]分組 Solution

題意:
給n個人,每個人有自己的意願以及工作經驗,11表示能當組長,22表示能當組員,33表示既能當組長又能當組員,並且有僱傭他的花費,現在需要將這些人分成kk組,每組22個人,2×kn2\times k\leq n,每個組有11個組長和11個組員,要求組長的工作經驗不小於組員的工作經驗,請問組成kk個隊的最小花費,或者這是不可能的。
考慮DP,首先要滿足組長經驗不小於組員,我們可以將這些人重新編號,如果他想當組長就編號爲33,兩個都可以就編號22,否則編號11,然後按照工作經驗爲第一關鍵字,編號爲第二大關鍵字排序,設f[i][j]f[i][j]表示現在編好了ii個組,還剩下jj個組員可以選擇。設當前人花費爲costcost,轉移分三種情況考慮:

  • 當前人編號爲33f[i+1][j1]=min(f[i+1][j1],f[i][j]+cost)f[i+1][j-1]=\min(f[i+1][j-1],f[i][j]+cost)
  • 當前人編號爲11f[i][j+1]=min(f[i][j+1],f[i][j]+cost)f[i][j+1]=\min(f[i][j+1],f[i][j]+cost)
  • 當前人編號爲22:綜合上面兩種情況轉移。
    code:code:
#include <bits/stdc++.h>
#define int long long
#define regi register int
int n,k;
long long f[5010][5010];
struct people{
	int exp;
	int cost;
	int wonder;
}p[1000001];
inline int read(){
	int r=0,w=0,c;
	for(;!isdigit(c=getchar());r=c);
	for(w=c^48;isdigit(c=getchar());w=w*10+(c^48));
	return r^45?w:-w;
}
bool cmp(people x,people y){
	return x.exp==y.exp?x.wonder<y.wonder:x.exp<y.exp;
}
main(){
	n=read(),k=read();
	if(n<k*2){
		puts("-1");
		return 0;
	}
	for(regi i=1;i<=n;++i){
	  p[i]={read(),read(),read()};
	  if(p[i].wonder==1)
	    p[i].wonder=3;
	  else if(p[i].wonder==2)
	    p[i].wonder=1;
	  else if(p[i].wonder==3)
	    p[i].wonder=2;
	}
	std::sort(p+1,p+n+1,cmp);
  for(regi i=0;i<=k+1;++i)
    for(regi j=0;j<=k+1;++j)
      f[i][j]=0x3f3f3f3f3f3f3f3fLL;
  f[0][0]=0;
	for(regi i=1;i<=n;++i)
	  for(regi j=k;j>=0;--j)
		  for(regi u=k;u>=0;--u){
		  	if(p[i].wonder==3&&j<k&&u)
		  	  f[j+1][u-1]=std::min(f[j+1][u-1],f[j][u]+1LL*p[i].cost);
		  	if(p[i].wonder==1&&u<k)
		  	  f[j][u+1]=std::min(f[j][u+1],f[j][u]+1LL*p[i].cost);
		  	if(p[i].wonder==2){
		  		if(j<k&&u)
					  f[j+1][u-1]=std::min(f[j+1][u-1],f[j][u]+1LL*p[i].cost);
		  	  if(u<k)
					  f[j][u+1]=std::min(f[j][u+1],f[j][u]+1LL*p[i].cost);
		  	}
		  }
	printf("%lld\n",f[k][0]==0x3f3f3f3f3f3f3f3fLL?-1LL:f[k][0]);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章