9.贪心算法

简单贪心

1.P10452 货仓选址 - 洛谷

cpp 复制代码
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;
const int N = 1e5+10;
LL a[N];
LL n;

int main()
{
	cin>>n;
	for(int i = 1;i <= n;i++)cin>>a[i];
	sort(a+1,a+1+n);//排序 
	LL sum = 0;
	//for(int i = 1;i <= n;i++)
	//{
	//	sum+=(abs(a[i]-a[(1+n)/2]));
	//}
	
	for(int i = 1;i <= n/2;i++)
	{
		sum += abs(a[i]-a[n+1-i]);
	}
	cout<<sum<<endl;
	return 0;
 } 

2.P1115 最大子段和 - 洛谷

cpp 复制代码
#include<iostream>

using namespace std;

typedef long long LL;

const int N = 2e5+10;
LL a[N];
LL n;

int main()
{
	cin>>n;
	for(int i = 1;i <= n;i++)cin>>a[i];
	
	LL sum = 0;LL ret = -1e5;
	for(int i = 1;i <= n;i++)
	{
		sum+=a[i];
		ret = max(sum,ret);
		if(sum < 0)sum = 0;
	 } 
	 cout<<ret<<endl;
	 return 0;
 } 

舍弃的想法很大胆,也很有风险,但通过证明,就可以表示通过

3. P1094 [NOIP 2007 普及组] 纪念品分组 - 洛谷

cpp 复制代码
#include<iostream>
#include<algorithm>
using namespace std;

int w,n;
const int N = 3e4+10;
int a[N];

int main()
{
	cin>>w>>n;
	for(int i = 1;i <= n;i++)cin>>a[i];
	//排序
	 sort(a+1,a+1+n);
	 int l = 1,r = n,ret = 0;
	 while(l <= r)
	 {
	 	//最小和最大相加小于w,符合 ,同时异位 
	 	if(a[l]+a[r]<=w)l++,r--;
	 	//l待定。r-- 
		 else
	 	{
	 		r--;
		 }
		 ret++;
	 }
	 cout<<ret<<endl;
	 return 0;
	
}

4.P1056 [NOIP 2008 普及组] 排座椅 - 洛谷

cpp 复制代码
#include<iostream>
#include<algorithm>
using namespace std;

int m, n, k, l, d;
const int N = 1010;

struct  node
{
	int index;//存行列的下标
	int cnt;//存取该行或者该列能隔开多少对同学
}row[N],col[N];

//按照cnt从大到小排列
bool cmp1(node& x, node& y)
{
	return x.cnt > y.cnt;
}
//按照下标从小到大排列
bool cmp2(node& x, node& y)
{
	return x.index < y.index;
}

int main()
{
	cin >> m >> n >> k >> l >> d;
	//初始化数组,赋值index
	for (int i = 1; i <= m; i++)row[i].index = i;
	for (int i = 1; i <= n; i++)col[i].index = i;
	//计算cnt
	while (d--)
	{
		int x, y, p, q; cin >> x >> y >> p >> q;
		if (x == p)col[min(y, q)].cnt++;
		else
			row[min(x, p)].cnt++;
	}
	//通过cnt把大的排在前面-->cmp1
	sort(row + 1, row + 1 + m, cmp1);
	sort(col + 1, col + 1 + n, cmp1);
	//把前k或者l大的按照下表从小到大进行排列
	sort(row + 1, row + 1 + k, cmp2);
	sort(col + 1, col + 1 + l, cmp2);
	//输出
	//行
	for (int i = 1; i <= k; i++)
	{
		cout << row[i].index << " ";
	}
	cout << endl;
	//列
	for (int i = 1; i <= l; i++)
	{
		cout << col[i].index << " ";
	}
	return 0;
}

1.把每一行和每一列可以隔开的同学记录到cnt中

2.按照cnt从大到小进行排列

3.按照index对前k或者l个进行从小到大的排列

4.输出前k 或 l的index下标

4.矩阵消除游戏

cpp 复制代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

int calc(int x)
{
	int ret = 0;
	while (x)
	{
		x = x & (x - 1);
		ret++;
	}
	return ret;
}

bool cmp(int x, int y)
{
	return x > y;
}

int n, m,k;
const int N = 100;
int a[N][N];
int col[N];

int main()
{
	cin >> n >> m >> k;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			cin >> a[i][j];
		}
	}
	int sum = 0, ret = 0;
	//暴力枚举所有的第一行
	for (int st = 0; st < (1 << n); st++)
	{
		sum = 0;
		int num_1 = calc(st);
		//超过就不要了
		if (num_1 > k)continue;

		memset(col, 0, sizeof(col));
		for (int i = 0; i < n; i++)
		{
			//加上当前行的数字
			for (int j = 0; j < m; j++)
			{
				if (((st >> i) & 1) == 1)
				{
					sum += a[i][j];
				}
				else
				{
					col[j] += a[i][j];
				}
			}
		}
		//对列进行从大到小排序,取前k - num_1个
		int remain = k - num_1;
		sort(col, col + m, cmp);
		for (int i = 0; i < remain; i++)sum += col[i];
		ret = max(ret, sum);
	}
	cout << ret << endl;
	return 0;
}

推公式

1.在确定好的顺序序列中,拿出相邻的两个元素

2.交换这两个元素,对前面和后面确定好顺序的序列的结果不造成影响

3.根据这两个原色交换前后的结果推导出排序的规

1.P1012 [NOIP 1998 提高组] 拼数 - 洛谷

cpp 复制代码
#include<iostream>

#include<algorithm>
using namespace std;

int n;
const int N = 25;
string st[N];

bool cmp(string& x, string& y)
{
	return x + y > y + x;
}

int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
		cin >> st[i];

	sort(st, st+n, cmp);
	for (int i = 0; i < n; i++)
		cout << st[i];
	return 0;
}

比较方法:两两元素相拼,

2.P2878 [USACO07JAN] Protecting the Flowers S - 洛谷

很震惊!!

1.在确定好的顺序序列中,拿出相邻的两个元素

2.交换这两个元素,对前面和后面确定好顺序的序列的结果不造成影响

3.根据这两个原色交换前后的结果推导出排序的

cpp 复制代码
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;

LL n;
const int N = 1e5+10;
struct node
{
	LL t;//时间
	LL d;//吃草速度 
}a[N]; 

bool cmp(node& x,node&y)
{
	return x.t*y.d < x.d*y.t;
}

int main()
{
	cin>>n;
	for(int i = 1;i <= n;i++)
	{
		cin>>a[i].t>>a[i].d;
	}
	sort(a+1,a+n+1,cmp);
	LL ret = 0,t = 0;
	for(int i = 1;i <= n;i++)
	{
		ret += a[i].d*t;
		t += 2*a[i].t;
	}
	cout<<ret<<endl;
 } 

3. P1842 [USACO05NOV] 奶牛玩杂技 - 洛谷

cpp 复制代码
#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;

const int N = 5e4+10;
int n;

struct node
{
	LL w;
	LL s;	
}a[N];
//推公式得到,把max中较小的放在前面,会让总体压力值变得较小 
bool cmp(node&x,node&y)
{
	return max(-x.s,x.w-y.s) < max(-y.s,y.w-x.s);
}

int main()
{
	cin>>n;
	for(int i = 1;i <= n;i++)
	{
		cin>>a[i].w>>a[i].s;
	}
	sort(a+1,a+1+n,cmp);
	
	LL w = 0;
	LL ret = -1e5;
	for(int i = 1;i <= n;i++)
	{
		ret = max(ret,w - a[i].s);
		w+=a[i].w;
	}
	cout<<ret<<endl;
	return 0;
	
 } 

哈夫曼树

1.P1090 [NOIP 2004 提高组] 合并果子 - 洛谷

cpp 复制代码
#include<iostream>
#include<queue>
#include<vector>
using namespace std;

typedef long long LL; 

priority_queue<LL,vector<LL>,greater<LL>>heap;

LL n;
int main()
{
	cin>>n;
	for(int i = 1;i <= n;i++)
	{
		LL x;cin>>x;
		heap.push(x);
	}
	LL sum = 0;
	while(heap.size()>1)
	{
		LL x = heap.top();heap.pop();
		LL y = heap.top();heap.pop();
		sum+=(x+y);
		heap.push(x+y);
	 } 
	 cout<<sum<<endl;
}

区间问题

这种题⽬的解决⽅式⼀般就是按照区间的左端点或者是右端点排序,然后在排序之后的区间上,根据 题⽬要求,制定出相应的贪⼼策略,进⽽得到最优解。

具体是根据左端点还是右端点排序?升序还是降序?⼀般是假设⼀种排序⽅式,并且制定贪⼼策略, 当没有明显的反例时,就可以尝试去写代码。

1.P1803 凌乱的yyy / 线段覆盖 - 洛谷

cpp 复制代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e6+10;
int n;
struct node
{
	int s;
	int e;
}a[N];

bool cmp(node&x,node&y)
{
	return x.s < y.s;
 } 

int main()
{
	cin>>n;
	for(int i = 1;i <= n;i++)
	{
		cin>>a[i].s;
		cin>>a[i].e;
	}
	
	sort(a+1,a+1+n,cmp);//按照起点开始由小到大的顺序排列
	int ret = 1;
	int r = a[1].e;
	for(int i = 2;i <= n;i++)
	{
		int right = a[i].e,left = a[i].s;
		if(left < r)//重叠了,不能参加,如果重叠的右端比前面那一个还小,那就贪,覆盖前面哪一个 
		{
			r = min(r,right);
		}
		else
		{
			ret++;//没有重叠,可以参加
			r = right;//更新较小的r 
		 } 
	}
	cout<<ret<<endl;
	return 0;
	 
} 

2.UVA1193 Radar Installation - 洛谷

按照左端点排序,互相重叠的区间是连续的
二维问题转化成一维问题
证明: 按照左端点排序,互相重叠的区间是连续的

cpp 复制代码
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;

const int N = 1e3+10;

int n,d;
struct node
{
	double l;
	double r;
}a[N];

bool cmp(node&x,node&y)
{
	return x.l < y.l;
}
int main()
{
	int cnt = 1;
	while(cin>>n>>d&&(n&&d))
	{
		int flag = 1;
		for(int i = 1;i <=		 n;i++)
		{
			int x,y;cin>>x>>y;
			if(y > d)flag = -1;
			//把二维映射到一维上去
			double l =  sqrt(d*d - y*y);
			a[i].l = x - l;
			a[i].r = x + l;
		}
		sort(a+1,a+1+n,cmp);
	int ret = 1;
	int r = a[1].r; 
	cout<<"Case "<<cnt<<": ";
	cnt++; 
	for(int i = 2;i <= n;i++)
	{
		int left = a[i].l,right = a[i].r;
		if(left<=r)//等于也可以扫到 
		{
			//扫描通过
			r =  min(r,right);
		}else
		{
			ret++;
			r = right;
		}
	}
	
	cout<<ret<<endl;
}
	return 0;
 } 

3.P2887 [USACO07NOV] Sunscreen G - 洛谷

cpp 复制代码
#include<iostream>
#include<algorithm> 
using namespace std;

const int N = 3e3+10;

int n,l;
struct node
{
	int l;//表示奶牛耐受的最小值//防晒霜的防晒值 
	int r;//奶牛耐受的最大值// 防晒霜的数量 
}a[N],b[N]; 

bool cmp(node&x,node&y)
{
	return x.l > y.l;
}
int main()
{
	cin>>n>>l;
	for(int i = 1;i <= n;i++)
	{
		cin>>a[i].l>>a[i].r;//输入奶牛耐受值 
	}
	for(int i = 1;i <= l;i++)
	{
		cin>>b[i].l>>b[i].r;//输入防晒霜的防晒值和数量 
	}
	//按照奶牛奶牛左端从大到小进行排序
	sort(a+1,a+1+n,cmp);
	//按照防晒霜防晒值从大到小进行排序
	sort(b+1,b+1+l,cmp);
	int ret = 0;
	for(int i = 1;i <= n;i++)
	{
		//选择一种防晒霜
		for(int j = 1;j <= l;j++)	
		{
			if(b[j].r == 0)continue;
			if(b[j].l<=a[i].r&&b[j].l>=a[i].l)
			{
				//符合条件,ret++,数量-- 
				ret++;
				b[j].r--;
				break;//选完一个就直接除去,免得后面的都没了 
			}
		}
	} 
	cout<<ret<<endl;
	return 0; 
}

4.P2859 [USACO06FEB] Stall Reservations S - 洛谷

cpp 复制代码
#include<iostream>
#include<queue> 
#include<algorithm>
using namespace std;
const int N = 5e4 + 10;
int n;
struct node
{
	int l;//牛牛的开始//该牛棚的结束时间 
	int r;//牛牛的结束 //该牛棚的编号 
	int num;//这只牛的编号 

	bool operator<(const node& y)const
	{
		return l > y.l;//创建小根堆 
	}
}a[N];
bool cmp(node& x, node& y)
{
	return x.l < y.l;
}
int res[N];//记录每只牛进入的牛棚顺序 
priority_queue<node> heap;//建议一个关于牛棚结束时间的小根堆,找出当前技术时间最早的,拉出来 
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i].l >> a[i].r;
		a[i].num = i;
	}
	//按照左端点从小到大排列
	sort(a + 1, a + 1 + n, cmp);
	int ret = 1;//记录牛棚状态
	heap.push({ a[1].r,1 });
	res[a[1].num] = 1; //一号牛进一号棚 
	for (int i = 2; i <= n; i++)
	{
		int l = a[i].l, r = a[i].r;
		int ete = heap.top().l;
		int num_peng = heap.top().r;
		if (ete >= l)//如果最短结束时间都>这只牛的开始的起始时间,那么就必须新开一个牛棚 
		{
			ret++;
			heap.push({ r,ret });
			res[a[i].num] = ret;
		}
		else//可以拿下 
		{
			heap.pop();//结束不要了 
			heap.push({ r,num_peng });//把这只牛推入彭中 
			res[a[i].num] = num_peng;
		}
	}
	cout << ret << endl;
	for (int i = 1; i <= n; i++)cout << res[i] << endl;
}

P2859 [USACO06FEB] Stall Reservations S - 洛谷

相关推荐
查理零世9 分钟前
【算法】 区间合并(附蓝桥杯真题) python
python·算法·蓝桥杯
Codingwiz_Joy25 分钟前
Day09 -实例:拿到加密密文进行解密
算法·安全·安全性测试
float_六七1 小时前
双指针算法
算法
BingLin-Liu1 小时前
图论之cruskal算法(克鲁斯卡尔)
数据结构·算法·图论
进取星辰1 小时前
PyTorch 深度学习实战(15):Twin Delayed DDPG (TD3) 算法
pytorch·深度学习·算法
strive-debug1 小时前
C语言之 条件编译和预处理指令
算法
Sacuki2 小时前
BP神经网络公式推导与代码实现
算法
山登绝顶我为峰 3(^v^)32 小时前
VSCode + CMake
ide·vscode·算法·计算机·编辑器
勇敢滴勇3 小时前
【C++】二叉搜索树(二叉查找树、二叉排序树)详解
开发语言·c++·算法·霍夫曼树
f狐0狸x3 小时前
【蓝桥杯每日一题】3.16
c++·算法·蓝桥杯