反悔贪心&&邻项交换

源自oi-wiki

邻项交换法

常与 d p dp dp 结合,先排序消除后效性再 d p dp dp

P1080 [NOIP2012 提高组] 国王游戏
题意:
国王和 n n n 个大臣左右手上分别有一个整数,国王在第一位, n n n 在后边拍成一列,一个大臣获得的金币数为:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
n n n 个大臣进行排序,最小化奖赏最多的大臣获得的金币
思路:
设排序后第 i i i 个大臣左右手上的数分别为 a i , b i a_i,b_i ai,bi ,考虑通过邻项交换法推导贪心策略。
s s s 表示第 i i i 个大臣前面所有人的 a i a_i ai 的乘积,那么第 i i i 个大臣得到的奖赏就是 s b i \frac{s}{b_{i}} bis,第 i + 1 i+1 i+1 个大臣得到的奖赏就是 s ∗ a i + 1 b i + 1 \frac{s*a_{i+1}}{b_i+1} bi+1sai+1
如果交换前更优当且仅当
m a x ( s b i , s ∗ a i b i + 1 ) < m a x ( s b i + 1 , s ∗ a i + 1 b i ) max(\frac{s}{b_i},\frac{s*a_{i}}{b_{i+1}})<max(\frac{s}{b_{i+1}},\frac{s*a_{i+1}}{b_i}) max(bis,bi+1sai)<max(bi+1s,bisai+1)
提出公因式 s s s
m a x ( 1 b i , a i b i + 1 ) < m a x ( 1 b i + 1 , a i + 1 b i ) max(\frac{1}{b_i},\frac{a_i}{b_{i+1}})<max(\frac{1}{b_{i+1}},\frac{a_{i+1}}{b_i}) max(bi1,bi+1ai)<max(bi+11,biai+1)
化成整式
m a x ( b i + 1 , a i ∗ b i ) < m a x ( b i , a i + 1 ∗ b i + 1 ) max(b_{i+1},a_i*b_i)<max(b_i,a_{i+1}*b_{i+1}) max(bi+1,aibi)<max(bi,ai+1bi+1)
然后排序就好了

01背包限制选择时的容量
选择时的容量有限制,不同的物品选择顺序出现了不同结果,不满足无后效性,可以采用贪心策略邻项交换法进行物品排序消除后效性
设当前容量为 j j j,物品体积为 p p p,满足容量大于等于 q q q 时才选择,价值为 w w w

  1. 考虑到状态转移方程 f [ j ] = m a x ( f [ j ] , f [ j − p ] + w ) ( j > = p   & &   j > = q ) f[j]=max(f[j],f[j-p]+w)(j>=p \ \&\& \ j>=q) f[j]=max(f[j],f[jp]+w)(j>=p && j>=q)
  2. 只有保证 f [ j − p ] f[j-p] f[jp] 最优时方程才能成立
  3. 设相邻物品 p 1 , q 1 , v 1 p_1,q_1,v_1 p1,q1,v1 p 2 , q 2 , v 2 p_2,q_2,v_2 p2,q2,v2
  4. 若要满足无后效性,也就是交换前更优,需满足 j − p 2 > = q 1   & &   j − p 1 > = q 2 j-p_2>=q_1 \ \&\& \ j-p_1>=q_2 jp2>=q1 && jp1>=q2
  5. q 1 − p 1 < = q 2 − p 2 q_1-p_1<=q_2-p_2 q1p1<=q2p2

排序后 d p dp dp 即可

美味菜肴
题意:
n n n 个食材, m m m 道菜,每道菜美味值为 a i a_i ai b i b_i bi 是食材不新鲜的速率, c i c_i ci 是做这个道菜需要的时间,如果在 t t t 时间完成这道菜,那么它的美味值为 a i − t ∗ b i a_i-t*b_i aitbi
T T T 时间做菜,求最大美味值,美味值可能是负数
思路:
邻项交换法,这个比较好推,和国王游戏差不多
初始时间为 0 0 0,考虑前两个
a 1 , b 1 , c 1 a_1,b_1,c_1 a1,b1,c1 a 2 , b 2 , c 2 a_2,b_2,c_2 a2,b2,c2
交换前更优当且仅当
a 1 − b 1 ∗ c 1 + a 2 − b 2 ∗ ( c 1 + c 2 ) > a 2 − c 2 ∗ b 2 + a 1 − b 1 ∗ ( c 1 + c 2 ) ⟹ b 1 ∗ c 2 > b 2 ∗ c 1 a_1-b_1*c_1+a_2-b_2*(c_1+c_2)>a_2-c_2*b_2+a_1-b_1*(c_1+c_2)\\ \Longrightarrow b_1*c_2>b_2*c_1 a1b1c1+a2b2(c1+c2)>a2c2b2+a1b1(c1+c2)b1c2>b2c1
排序后 d p dp dp 即可

反悔贪心

P2949 [USACO09OPEN]Work Scheduling G
贪大小+并查集
经典的并查集应用
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 2e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
struct node{
	int d, p;
	bool operator<(const node &B){
		return p > B.p;
	}
}a[maxn];
unordered_map <int, int> ma;

int find(int x){
	if(!ma.count(x)) return x;
	else return ma[x] = find(ma[x]);
}
void work()
{
	cin >> n;
	for(int i = 1; i <= n; ++i){
		cin >> a[i].d >> a[i].p;
	}
	sort(a + 1, a + 1 + n);
	ll ans = 0;
	for(int i = 1; i <= n; ++i){
		int x = find(a[i].d);
		if(x >= 1) ans += a[i].p, ma[x] = x - 1;
	}	
	cout << ans;
}

int main()
{
	ios::sync_with_stdio(0);
//	int TT;cin>>TT;while(TT--)
	work();
	return 0;
}

贪截至时间+反悔贪心
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 2e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
struct node{
	int d, p;
	bool operator<(const node &B){
		return d < B.d;
	}
}a[maxn];
priority_queue <ll, vector<ll>, greater<ll> > q;

void work()
{
	cin >> n;
	for(int i = 1; i <= n; ++i){
		cin >> a[i].d >> a[i].p;
	}
	sort(a + 1, a + 1 + n);
	ll ans = 0;
	for(int i = 1; i <= n; ++i){
		if(a[i].d <= q.size()){
			if(q.top() < a[i].p){
				ans += a[i].p - q.top();
				q.pop();
				q.push(a[i].p);
			}
		}
		else {
			ans += a[i].p;
			q.push(a[i].p);
		}
	}	
	cout << ans;
}

int main()
{
	ios::sync_with_stdio(0);
//	int TT;cin>>TT;while(TT--)
	work();
	return 0;
}

哦唔西迪西小姐
思路:
反悔贪心,但是并不需要优先队列维护,很妙
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define mem(x, d) memset(x, d, sizeof(x))
#define eps 1e-6
using namespace std;
const int maxn = 2e6 + 9;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll n, m;
int a[maxn], p[maxn], b[maxn];
vector <int> v1, v2;

ll f(){// 走 0 
	vector <int> v;
	ll ans = 0;
	for(int i = 1; i <= n; ++i){
		if(b[i]) v.push_back(max(-p[i], a[i] - p[i]));
		else{
			ans += max(a[i], 0);//直接选
            v.push_back(-p[i] - max(a[i], 0));// 
		}
	}
	sort(all(v), greater<int>());
	for(int i = 0; i < v.size() && i < m; ++i){
		ans += max(0, v[i]);
	}
	return ans;
}
void work()
{
	cin >> n >> m;
	for(int i = 1; i <= n; ++i) cin >> a[i];
	for(int j = 1; j <= n; ++j) cin >> p[j];
	for(int i = 1; i <= n; ++i)	cin >> b[i];
	ll ans = f();
	for(int i = 1; i <= n; ++i) b[i] = !b[i];
	ans = max(ans, f());
	cout << ans;
}

int main()
{
	ios::sync_with_stdio(0);
//	int TT;cin>>TT;while(TT--)
	work();
	return 0;
}

C2. Potions (Hard Version)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值