2025/10/02皇后游戏
题解:P2123 皇后游戏
题目分析
这道题是 NOIP 2012 国王游戏问题的变种。题目要求我们重新排列大臣的顺序,使得获得奖金最多的大臣所获奖金尽可能少。
奖金计算规则
设第 \(i\) 位大臣左手上的数为 \(a_i\),右手上的数为 \(b_i\),则:
- 第 \(1\) 位大臣的奖金:\(c_1 = a_1 + b_1\)
- 第 \(i\) 位大臣的奖金(\(i \geq 2\)):\(c_i = \max(c_{i-1}, \sum_{j=1}^{i} a_j) + b_i\)
解题思路
关键观察
与国王游戏类似,我们需要找到一个合适的大臣排列顺序。通过分析可以发现,大臣的排列顺序会影响最终的奖金最大值。
排序策略
代码中的排序规则是核心:
bool cmp(node a, node b) {
if(a.x <= a.y && a.x <= b.x || b.x <= a.x && b.x <= b.y)
return a.x != b.x ? a.x < b.x : a.y > b.y;
return a.y != b.y ? a.y > b.y : a.x < b.x;
}
这个比较函数的意思是:
- 如果大臣A满足 \(a_x \leq a_y\) 且 \(a_x \leq b_x\),或者大臣B满足 \(b_x \leq a_x\) 且 \(b_x \leq b_y\),那么:
- 优先按 \(x\) 升序排列
- \(x\) 相同时按 \(y\) 降序排列
- 否则:
- 优先按 \(y\) 降序排列
- \(y\) 相同时按 \(x\) 升序排列
算法流程
- 读取输入数据
- 按照上述规则对大臣进行排序
- 计算排序后的奖金序列:
- 维护前缀和
l表示当前已处理大臣的左手数值之和 - 维护当前最大值
ans - 对于每个大臣,更新前缀和后计算其奖金
- 维护前缀和
代码实现
#include<bits/stdc++.h>
using namespace std;
int T = 1, n;
long long l, ans;
struct node {
int x, y, id;
} a[20005];
bool cmp(node a, node b) {
if(a.x <= a.y && a.x <= b.x || b.x <= a.x && b.x <= b.y)
return a.x != b.x ? a.x < b.x : a.y > b.y;
return a.y != b.y ? a.y > b.y : a.x < b.x;
}
int main() {
// cin >> T;
while(T--) {
l = 0; ans = 0;
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i].x >> a[i].y;
a[i].id = i;
}
sort(a + 1, a + n + 1, cmp);
for(int i = 1; i <= n; i++) {
l += a[i].x;
if(ans < l)
ans = l + a[i].y;
else
ans += a[i].y;
}
cout << ans << "\n";
for(int i = 1; i <= n; i++)
cout << a[i].id << " ";
}
return 0;
}
示例分析
样例1
输入:
1
3
4 1
2 2
1 2
排序后的大臣顺序为:3号(1,2)、2号(2,2)、1号(4,1)
计算过程:
- 大臣3:奖金 = 1 + 2 = 3
- 大臣2:奖金 = max(3, 1+2) + 2 = max(3,3) + 2 = 5
- 大臣1:奖金 = max(5, 1+2+4) + 1 = max(5,7) + 1 = 8
输出:8
复杂度分析
- 时间复杂度:\(O(T \cdot n \log n)\),主要来自排序操作
- 空间复杂度:\(O(n)\),用于存储大臣信息
总结
这道题的关键在于找到合适的大臣排列顺序。通过特定的排序规则,我们可以最小化奖金的最大值。排序策略综合考虑了大臣左右手数值的关系,优先处理那些"左手数值较小"或者"右手数值较大"的大臣,从而平衡奖金分配。
这种贪心策略的题目需要仔细分析问题特性,找到合适的比较规则,是算法竞赛中的经典题型。
#include<bits/stdc++.h>
using namespace std;
int T,n;
long long l,ans;
struct node{
int x,y,id;
}a[20005];
bool cmp(node a,node b)
{
if(a.x<=a.y&&a.x<=b.x||b.x<=a.x&&b.x<=b.y) return a.x!=b.x?a.x<b.x:a.y>b.y;
return a.y!=b.y?a.y>b.y:a.x<b.x;
}
int main()
{
cin>>T;
while(T--)
{
l=0;ans=0;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].x>>a[i].y;
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
{
l+=a[i].x;
if(ans<l) ans=l+a[i].y;
else ans+=a[i].y;
}
cout<<ans<<"\n";
for(int i=1;i<=n;i++) cout<<a[i].id<<" ";
}
return 0;
}

浙公网安备 33010602011771号