贪心找零:
- 最新版的人民币面值有:1角,5角,1元,10元,20元,50元,请分析这套面值方案可以使用贪心法找零吗?
可以使用贪心法找零,首先对于1角,5角,1元,10元,20元,5种钞票的找零,由于他们之间存在倍数关系,因此一定能够采用贪心策略。
那么现在,我们是不是可以肯定出,在上述的6张包括50的钞票中,50元以下的面值是一定能够采用贪心的(用前面我们提到的5张)。
那么现在,对于50元,我们发现也是能够采用贪心策略。而同期不包括50的贪心却需要(20,20,10),因此我们可以发现50的贪心策略可行。
那我们是不是能够确认50内的贪心优化是最好的。
那么我们接下来考虑60范围内(包括60)的数据,我们采取的考虑一定是50+剩余不足(10元)的部分,因此确定能够采用贪心策略。
接下来考率70范围内,考虑50+10+剩余(pass20+20+20+剩余);因此70以内也可以
接下来考虑80范围内,考虑50+20+剩余;显然无误;也可以贪心找零。
接下来确定90,100,同理考虑仍然可以。
对于100以上部分,我们可知一定会采用两张五十替代,剩余部分与上述相同。
对于贪心和动态规划来说,没有十分明确的对症,实际题目的判断应该是在无法 明确倍数关系时,能够确定一定能够使用,否则尽量采取动态策略。
多机调度问题:
- 问题描述
设有n个独立的作业{1, 2, …, n},由m台相同的机器{M1, M2, …, Mm}进行加工处理,作业i所需的处理时间为ti(1≤i≤n),每个作业均可在任何一台机器上加工处理,但不可间断、拆分。多机调度问题要求给出一种作业调度方案,使所给的n个作业在尽可能短的时间内由m台机器加工处理完成。 - 设7个独立作业{1, 2, 3, 4, 5, 6, 7}由3台机器{M1, M2, M3}加工处理,各作业所需的处理时间分别为{2, 14, 4, 16, 6, 5, 3}
#include<iostream>
#include<algorithm>
using namespace std;
#define N 10000
int n,m;
int machineWork[N][N];
int workTime[N];
int rear[N];
//多机调度问题解决
/**
问题描述
设有n个独立的作业{1, 2, …, n},由m台相同的机器{M1, M2, …, Mm}进行加工处理,作业i所需的处理时间为ti(1≤i≤n),每个作业均可在任何一台机器上加工处理,但不可间断、拆分。多机调度问题要求给出一种作业调度方案,使所给的n个作业在尽可能短的时间内由m台机器加工处理完成。
设7个独立作业{1, 2, 3, 4, 5, 6, 7}由3台机器{M1, M2, M3}加工处理,各作业所需的处理时间分别为{2, 14, 4, 16, 6, 5, 3}。
**/
struct Work{
int number;
int time;
}work[N];
bool cmp(Work a,Work b){
if(a.time==b.time)
return a.number>b.number;
return a.time>b.time;
}
void assign_work(){
// 先给所有机器分配任务
fill(rear,rear+m,0);
for(int i=0;i<m;i++){
workTime[i]=work[i].time;
machineWork[i][0]=work[i].number;
}
//给剩下的作业分配最空闲机器
for(int i=m;i<n;i++){
//循环判断哪个机器最闲
int k=0;
for(int j=1;j<m;j++){
if(workTime[j]<workTime[k]){
k=j;
}
}
rear[k]=rear[k]+1;
machineWork[k][rear[k]]=work[i].number;
workTime[k]+=work[i].time;
}
}
void output(){
//输出
cout<<"各机器工作的作业情况为" ;
for(int i=0;i<m;i++){
cout<<"第"<<i+1<<"台机器作业为:";
for(int j=0;j<=rear[i];j++){
cout<<"作业"<<machineWork[i][j]<<" ";
}
cout<<"工作总时长为"<<workTime[i]<<endl;
}
}
void input(){
cin>>n>>m;
for(int i=0;i<n;i++){
cin>>work[i].time;
work[i].number=i+1;
}
//根据
sort(work,work+n,cmp);
//打印
/**
for(int i=0;i<n;i++){
cout<<work[i].time<<" ";
}
**/
assign_work();
output();
}
int main(){
input();
return 0;
}
哈夫曼编码:
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
#define N 10000
int n;
string path[N];
struct Node{
int number;
int W;
int Lchild;
int Rchild;
int Father;
string Rec;
int L;
}node[N];
bool cmp_w(Node a,Node b){
return a.W<b.W;
}
bool cmp_n(Node a,Node b){
return a.number<b.number;
}
void input(){
cin>>n;
for(int i=1;i<=n;i++){
cin>> node[i].W;
node[i].number=i;
}
}
void createNode(int k){
//初始化创建节点的条件
int t=k+n;
node[t].number=t;
int l,r;
l=2*k-1,r=2*k;
//父节点初始
node[t].number=t;
node[t].W=node[l].W+node[r].W;
node[t].Lchild=node[l].number;
node[t].Rchild=node[r].number;
//孩子初始
node[l].Father=node[t].number;
node[r].Father=node[t].number;
node[l].Rec="0";node[r].Rec="1";
sort(node+1,node+n+k+1,cmp_w);
}
void createTree(){
//创建n-1个非叶子节点
for(int i=1;i<=n-1;i++){
createNode(i);
}
}
/**
void output(){
for(int i=1;i<=2*n-1;i++){
cout<<node[i].W;
}
}
**/
void Huffman(){
sort(node+1,node+2*n,cmp_n);
for(int i=1;i<=n;i++){ //对所有叶子节点
path[i]="";
int k=i;
node[i].L=0;
while(node[k].Father!=0){
path[i]=node[k].Rec+path[i]+""; //路径放在前面
node[i].L++;
k=node[k].Father;
}
}
//带权路径长度是
int totalweight=0;
for(int i=1;i<=n;i++){
totalweight+=node[i].W*node[i].L;
cout<<"节点"<<i<<"的编码为"<<path[i]<<endl;
}
cout<<"带权路径长度为:"<<totalweight<<endl;
}
int main(){
input();
sort(node+1,node+n+1,cmp_w);
createTree();
Huffman();
//output();
}
/**
输入:
最短路径问题(Dijkstra)
#include<iostream>
#include<algorithm>
#include<queue>
#define N 1000
const int INF=100000;
using namespace std;
/**测试用例
5 6 0
0 1 10
0 2 3
1 2 1
1 3 2
2 1 4
2 3 8
**/
/**
结果
0
7
3
9
INF
**/
int main(){
int n,m,s;
cin>>n>>m>>s;
//输入边点间距
vector<vector<pair<int,int>>> graph(n);
for(int i=0;i<m;i++){
int u,v,w;
cin>>u>>v>>w;
graph[u].push_back(make_pair(v,w));
}
//建立优先队列,用来保存最短路径和点
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> pq;
//建立距离表
vector<int> dist(n,INF);
dist[s]=0;
//将起始点加入优先队列
pq.push(make_pair(0,s));
while(!pq.empty()) {
//取节点
int u=pq.top().second;
pq.pop();
//遍历该节点的相邻节点
for(auto next:graph[u]){
int v=next.first;
int w=next.second;
//如果这个节点到原点距离更短,能够刷新
if(dist[v]>dist[u]+w){
dist[v]=dist[u]+w;
//节点入队
pq.push(make_pair(dist[v],v));
}
}
}
//输出
for(int i=0;i<n;i++){
cout<<dist[i]<<" ";
}
return 0;
}
打水问题
- 有n个人排队到r个水龙头去打水,他们装满水桶的时间t1,t2,```,tn为整数且各自不相等,应如何安排打水顺序才能使他们总共花费时间最少
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
int time_spend[n];
for(int i=0;i<n;i++){
cin>>time_spend[i];
}
//进行排序
sort(time_spend,time_spend+n);
//进行装水
int water_work[m][n];
int total_time=0;
//先前两个人装水
int i;
vector<int> time_work(m,0); //记录每列的总时间
for(i=0;i<m;i++){
water_work[i][0]=time_spend[i];
time_work[i]+=water_work[i][0];
total_time+=time_spend[i];
}
//定义指向水龙头的数组
vector<int> pointer(m,0);
while(i<n){
int point=1; //查找当下时间最短的
int min=0;
while(point<m){
if(time_work[point]<time_work[min]){
min=point;
}
point++;
}
water_work[min][++pointer[min]]=water_work[min][pointer[min]-1]+time_spend[i++];
total_time+=water_work[min][pointer[min]];
}
cout<<total_time;
}
分糖果问题
一群孩子做游戏,现在请你根据游戏得分来发糖果,要求如下:
-
每个孩子不管得分多少,起码分到一个糖果。
-
任意两个相邻的孩子之间,得分较多的孩子必须拿多一些糖果。(若相同则无此限制)
给定一个数组 arrarr 代表得分数组,请返回最少需要多少糖果。
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int n;
cin>>n;
int score[n+1];
for(int i=1;i<=n;i++){
cin>>score[i];
}
int candy[n+1];
fill(candy,candy+n,1);
int totalcandy=n;
int point=0;
while(point<n){
if(score[point]<score[point+1]){
candy[point+1]++;
totalcandy++;
}
point++;
}
while(point>=1){
if(score[point]>score[point+1]){
candy[point]++;
totalcandy++;
}
point--;
}
cout<<totalcandy<<endl;
}
/**
9
8 9 2 3 4 7 3 1 8
输入1
3
1 0 2
5
输入2
3
1 2 2
4
**/
最小生成树
#include<iostream>
using namespace std;
#include<vector>
#define N 100
#define INF 100000
int n,m,s;
int visited[N];
int dist[N];
int sum;
int graph[N][N];
/**
* 假设S是顶点的全集,V是已经访问的节点,S-V代表没有访问的节点,用dist[i]表示到V-(S-V)某顶点的最短距离
*/
int prim(int s){
dist[s]=0;
for(int i=1;i<=n;i++){
//TODO
int cur=-1;
//添加下一下已经访问节点
for(int j=1;j<=n;j++){
//TODO
if(!visited[j]&&(cur==-1||dist[j]<dist[cur])){
cur=j;
}
}
//
if(dist[cur]==INF)
return INF;
visited[cur]=1;
sum+=dist[cur];
//对增添的点进行重新的dist赋值
for(int k=1;k<=n;k++){
if(!visited[k]&&graph[cur][k]<dist[k]){
dist[k]=graph[cur][k];
}
}
}
return sum;
}
int main(){
/**
* n:点的个数
* m:边的条数
* s:起始点
*/
cin>>n>>m;
//输入图
fill(graph[1],graph[1]+N*N,INF);
fill(dist,dist+N,INF);
// for(int i=1;i<=n;i++){
// //TODO
// cout<<dist[i];
// }
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
graph[u][v]=w;
graph[v][u]=w;
}
// visited[0]=1;
//遍历寻找下一个点
int value = prim(1);
if(value >= INF) puts("impossible");
else printf("%d\n",sum);
return 0;
}