萌新求救90分
查看原帖
萌新求救90分
220342
梦语小猪头楼主2020/9/14 13:00

状压DP,思路:枚举合法状态,在每次更新Fi时,判断当前子集是否是i的合法子集,v记录最大时间,k表示是从哪里转移过来的 转移式Fi = min Fk + vj; code:

#include<cstdio>
#include<iostream>
using namespace std;

const int MAXN = 1e7 + 17;
const int INF = 1e9 + 1;

int F[MAXN],t[MAXN],w[MAXN],s[MAXN],v[MAXN],s0,n,W;

void gets()
{
	int cost,time;
	for(int i = 1;i < (1 << n);i += 1)
	{
		cost = 0;
		time = 0;
		for(int j = 1;j <= n;j += 1)
		{
			if((i & (1 << (j - 1))) == 0)continue;
			cost += w[j];
			time = max(time,t[j]);
			if(cost > W)break;
		}
		if(cost <= W){
			s[++s0] = i;
			v[s0] = time;
		}
	}
}

bool check(int u,int v)
{
	for(int i = 1;i <= n;i += 1)
		if((u >> (i - 1)) && !(v >> (i - 1)))return 0;
	return 1;
}

int main()
{
	cin >> W >> n;
	for(int i = 1;i <= n;i += 1)
		cin >> t[i] >> w[i];
	gets();
	F[0] = 0;
	for(int i = 1;i < (1 << n);i += 1)
	{
		F[i] = INF;
		for(int j = 1;j <= s0;j += 1)
		{
			if(s[j] > i)break;
			if(!check(s[j],i))continue;
			int k = i - s[j];
			F[i] = min(F[i],F[k] + v[j]);
		}
	}
	cout << F[(1 << n) - 1] << endl;;
	return 0;
}
2020/9/14 13:00
加载中...