专栏文章

题解:P13195 [GCJ 2016 #1C] Senate Evacuation

P13195题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miomtnyv
此快照首次捕获于
2025/12/02 21:46
3 个月前
此快照最后确认于
2025/12/02 21:46
3 个月前
查看原文

题意分析

这道题使用贪心,每次都优先疏散当前人数最多的政党,这样可以尽量避免某个党派形成绝对多数。因为可以疏散一个或者两个议员,我们不妨优先尝试疏散两个议员。如果疏散两个议员会导致失败,则回溯第二个人,只疏散一人。因为题目保证存在一种满足题意的疏散方式,所以我们这样的操作是可以得到一组答案的。

实现方式

由于每次都需要取出人数最多的党,可以使用优先队列维护人数最多的政党,每一个元素存储党派的人数和代号。实现过程如下:
  • 每次从堆中取出人数最多的党,疏散两个人
  • 模拟疏散两个人,更新人数
  • 检查疏散后是否依旧合法,循环每个党派
  • 若合法,就疏散这两个人
  • 若不合法,回溯第二人,只疏散第一个人

代码

CPP
#include<bits/stdc++.h> 
using namespace std;

typedef pair<int,int> party;
priority_queue<party> q;
int a[30],T,n;

int main(){
	cin>>T;
	for(int t=1;t<=T;t++){
		cin>>n;
		int sum=0;
		for(int i=0;i<n;i++){
			cin>>a[i];
			q.push({a[i],i});
			sum+=a[i]; //记录总人数
		}
		
		cout<<"Case #"<<t<<": ";
		
		while(sum){
			//尝试疏散一人 
			auto [x1,i1]=q.top();
			q.pop();
			x1--;
			sum--;
			string step=""; //记录疏散过程 
			step+='A'+i1;
			
			if(!q.empty()){ //还有其他党派 
				auto[x2,i2]=q.top();
				q.pop();
				x2--;
				sum--;
				//模拟疏散这两人 
				a[i1]=x1;
				a[i2]=x2;
				bool valid=1;
				for(int i=0;i<n;i++)
					if(a[i]>sum/2) //有过半的党派 
						valid=0;
						
				if(valid){
					step+='A'+i2;
					if(x2)
						q.push({x2,i2});
				}else{
					//回溯第二人 
					x2++;
					sum++;
					a[i2]++;
					q.push({x2,i2});
				}
			}
			
			//疏散第一人 
			a[i1]=x1;
			if(x1)
				q.push({x1,i1});
			cout<<step<<' ';
		}
		cout<<'\n';
	}
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...