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, ' ');
}
}