贪心算法

1.背包相关问题

部分背包问题 有n个物体,第i个物体的重量为wi,价值为vi。在总重量不超过c的情况下让总价值尽量高。

分析:贪心算法,只顾眼前,选取价值最大且相对较轻的物体,所以可以用“价值/重量”来选择,结果从大到小,直到重量超过c。

乘船问题 有n个人,第i个人重量为wi。每艘船的最大载重量均为c,且最多只能乘2个人。用最少的船装载所有人。

分析:i表示最轻的人,j表示最重的人,j每次都向左移动,直到重量能和i表示 的坐一条船,而大于j的人则只能单独坐一条船。

2。区间相关问题

选择不相交区间 给定n个开区间(a,b)选择尽量多个不相交区间。

先把区间按b的大小排序,当b区间包含a区间,则选a,开始则选择第一个区间,然后选和第一个区间不相交的区间。再把它当作第一个区间。依次进行。


#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{

	int a,b;
        bool operator<(node q1,node q2){
	return q1.b==q2.b?q1.a>q2.b:q1.b<q2.b;
}

}q[100];
int m,n;
int main(){
	scanf("%d",&m);
	while(m--){
		scanf("%d",&n);
		for(int i=0 ;i<n ;i++){
			scanf("%d%d",&q[i].a,&q[i].b);
		}
		sort(q,q+n);
		int j=q[0].b;
		int cnt = 1;
		for(int i=1 ;i<n ;i++){
			if(q[i].a>j){//不相交
				cnt++;
				j = q[i].b;//更新“第一个”
			}
		}
		printf("%d\n",cnt);

	}
	return 0;
}

区间选点问题 数轴上有n个闭区间[a,b]。取尽量少的点,使得每个区间内都至少有一个点(不同区间的点可以是同一个)。

分析:同样区间按b从小到大排序,第一次先选第一个区间的最后一个点,再将这个点包含于的最后一个区间的下一个区间当作第一个区间。

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{

	int a,b;
        bool operator<(node q1,node q2){
	return q1.b==q2.b?q1.a>q2.b:q1.b<q2.b;
}

}q[100];
int m,n;
int main(){
	scanf("%d",&m);
	while(m--){
		scanf("%d",&n);
		for(int i=0 ;i<n ;i++){
			scanf("%d%d",&q[i].a,&q[i].b);
		}
		sort(q,q+n);
		int k=q[0].b;
		int cnt = 1;
		for(int i=1 ;i<n ;i++){
			if(q[i].a>k){//不在区间内
				cnt++;//点的数量
				k = q[i].b;//更新“第一个”
			}
		}
		printf("%d\n",cnt);

	}
	return 0;
}

区间覆盖问题 数轴上有n个闭区间[a,b],选择尽量少的区间覆盖一条指定线段[s,t]。

分析:先将所有区间进行预处理,将它们都更新为[s,t]之间的有效部分。再按a从小到大排序,如果第一个区间a大于s,无解,然后再将第一个区间的b为起点,再进行筛选。

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{

	int a,b;
        bool operator<(node q1,node q2){
	return q1.a==q2.a?q1.a<q2.a:q1.b>q2.b;
}

}q[100];
int m,n;
int main(){
	scanf("%d",&m);
	while(m--){
                int s,t;
                scanf("%d%d",&s,&t);
		scanf("%d",&n);
		for(int i=0 ;i<n ;i++){
			scanf("%d%d",&q[i].a,&q[i].b);
                        //if(q[i].a<s)q[i].a=s;
                        //if(q[i].b>t)q[i].b=t;
		}
		sort(q,q+n);
		int k=s;
		int cnt = 1,j,i=0;
                int len=0,tlen=0;
                while(len<t-s){
                    tlen=0;
		   for(i ;i<n;i++){
		 	if(q[i].a<=k){
				if(q[i].b-k>tlen){//找出长度最大的区间
                                   j=i;
                                   tlen=q[i].b-k;
                                }	
	                }else break;//大于这个点,那么后面也不会再有了
		   }
                  if(tlen=0){break;cout<<"no";}
                  cnt++;//点的数量
                  k=q[i].b;
                  len+=tlen;
                }
		printf("%d\n",cnt);

	}
	return 0;
}

3.Huffman编码

本质也是贪心的一种,每次都找最小的权值。

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

struct MyStruct
{
	int weight;
	char c;
	int parent;
	int lchild;
	int rchild;
}p[100];
char s[1000];
int len = 1;
void init() {
	int i = 0;
	for (; s[i] != '\0'; i++) {
		int flag = 1;
		for (int j = 0; j < i;j++ ) {
			if (s[j] == s[i]) {//字符已经出现过了
				flag = 0;
				break;
			}
		}
		if (flag) {//没有出现过
			p[len].c = s[i];
			p[len].weight = 1;
			for (int k = i + 1; s[k] != '\0'; k++) {
				if (s[k] == s[i])p[len].weight++;
			}
			len++;
		}
	}
	len--;
}
void createht() {
	for (int i = 0; i < 2 *len - 1; i++) {
		p[i].parent = 0;
		p[i].lchild = 0;
		p[i].rchild = 0;
		if(i>len)
		p[i].c = NULL;
	}
	for (int i = len + 1; i <= 2 * len - 1; i++) {
		int n1, n2; int j = 1;
		for ( j = 1; j < i; j++) {
			if (!p[j].parent) {
				n1 = j;
				break;
			}
		}
		for ( ; j < i; j++) {
			if (!p[j].parent)
			n1 = p[n1].weight > p[j].weight ? j : n1;//找出最小的
		}
		p[i].lchild = n1;
		p[n1].parent = i;
		for (j=1; j < i; j++) {
			if (!p[j].parent) {
				n2 = j;
				break;
			}
		}
		for (; j < i; j++) {
			if (!p[j].parent)
			n2 = p[n2].weight > p[j].weight ? j : n2;//找出第二小的
		}
		p[i].rchild = n2;
		p[n2].parent = i;
		p[i].weight = p[n1].weight + p[n2].weight;
	}
}

void code(int root,char *A,int k,char tp) {
	A[k] = tp;
	if (p[root].c != NULL) {
		A[k+1] = '\0';
		cout <<p[root].c<< A << endl;
	}
	if(p[root].lchild)
	code(p[root].lchild, A, k + 1, '0');
	if(p[root].rchild)
	code(p[root].rchild, A, k + 1, '1');
}

int main() {
	while (cin >> s) {
                len=1;
		char A[100];
		init();
		createht();
		code(2 * len - 1, A, 0, ' ');
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值