//return a>=b 降序
分治法
最大子段和
//C[i]=max{C[i-1]+A[i],A[i]}
//C[1]=A[1]
b[0]=0;
int MAX=0;
for(int i=1;i<=n;i++)
{
b[i]=max(b[i-1]+a[i],a[i]);
if(MAX<b[i])
MAX=b[i];
}
cout<<MAX;//不是输出最后一个
//是要输出过程中最大的一个
求第k小元素问题
- 快排
众数问题
- 假设mid即为所求 不断更新
void split(int a[],int n,int &l,int &r)
{
int mid=n/2;
for(l=mid;l>=0;l--)
{
if(a[l]!=a[mid])
{
break;
}
}
for(r=mid+1;r<n;r++)
{
if(a[r]!=a[mid])
{
break;
}
}
}
void getnumMax(int &num,int &numMax,int a[],int n)
{
int l,r;
split(a,n,l,r);
int mid=n/2;
int length=r-l-1;
//update
if(num<length)
{
num=length;
numMax=a[mid];
}
if(l+1>length)
{
getnumMax(num,numMax,a,l+1);
}
if(n-r>length)
{
getnumMax(num,numMax,a+r+1,n-r);
}
}
邮局选址问题
-
使用快排排序求出中位数即可
-
int QKPass(int r[],int low,int high) { int x=r[low]; while(low<high) { while(low<high&&r[high]>=x) high--; if(low<high) { r[low]=r[high]; low++; } while(low<high&&r[low]<x) low++; if(low<high) { r[high]=r[low]; high--; } } r[low]=x; return low; } void QKSort(int a[],int low,int high) { int pos; if(low<high) { pos=QKPass(a,low,high); QKSort(a,low,pos-1); QKSort(a,pos+1,high); } }
输油管道问题
- 和邮局选址相同 使用快排而后得到中位数即可 不过距离只算y
集合划分问题
- 找出关系式
f(n,m) = f(n-1,m-1) + m * f(n-1,m)
- n为元素个数 m为非空子集个数
- 新增元素单独分为一类 + 新增元素任意添加到已有集合
整数因子分解问题
-
相同因子 顺序不同 — 算不同种
-
n%i == 0 n/i
int i=2;
if(n==1)
sum++;
else
{
while(i<=n)
{
if(n%i==0)
f(n/i);
i++;
}
}
贪心法
会场安排问题
- 利用结构体将数据储存起来(start,end,flag)
int num=n;
int start=0;
int count=0;
while(num!=0)
{
for(int i=0;i<n;i++)
{
if(a[i].begin>start && a[i].flag==0)
{
a[i].flag=1;
start=a[i].end;
num--;
}
}
start=0;//到此即已使用一个会客厅 剩余需安排至其他会客厅
count++;
}
程序储存问题
- 使用sort进行排序,从小开始储存
最优分解问题
-
根绝均值不等式的成立条件可知,若 a + b = const,则 |a - b| 越小,a·b越大
-
将n分成从2开始的连续自然数的和,如果最后剩下一个数,将此数在后项优先的方式下均匀地分给前面各项
-
最后一项不要 算出已得到的和需要的差值 从后往前均匀分1给前面的数
for(int i=2;i<n;i++) { sum=sum+i; if(sum==n) { last=i; for(int j=2;j<=i;j++) { aul=aul*j; cout<<aul; } break; } else if(sum>n) { int x=i-(sum-n); //核心差值 int jj; for(int j=2;j<=i-1-x;j++) { aul=aul*j; cout<<j<<endl; } jj=i-x+1; //均匀+1 for(int n=1;n<=x;n++) { aul=aul*jj; cout<<jj<<endl; jj++; } cout<<aul; break; } }
最少硬币问题
动态规划法
最少费用购物(PASS)
独立问题最优调度(PASS)
双调旅行售货员(PASS)
最少硬币问题
-
硬币数量有限
//倒着出发 int dp[m+1]; memset(dp,INF,sizeof(dp)); dp[0]=0; for(int i=0;i<n;i++) for(int j=1;j<=C[i];j++) for(int k=m;k>=T[i];k--) dp[k]=min(dp[k-T[i]]+1,dp[k]); cout<<dp[m];
-
硬币数量无限
//正着出发 从1开始 int dp[k+1]; for(int i=1;i<=k;i++) dp[i]=k+1;//最小硬币面值为1 最大硬币数为k dp[0]=0; for(int j=1;j<=k;j++) for(int i=0;i<n;i++) { if(j>=c[i]) //注意 这个地方是>= { dp[j]=min(dp[j],dp[j-c[i]]+1); } } cout<<dp[k];
回溯与分支限界
0-1背包问题
memset(dp,0,sizeof(dp)); //初始赋值0
for(int i=1;i<=n;i++)
cin>>volume[i]>>value[i];//从1开始
int maxNum =0;
for(int i=1;i<=n;i++)
for(int j=0;j<=v;j++)
{
dp[i][j] = dp[i-1][j];//初始填充 防止j<volume[i]情况下该步为0 影响后续操作
if(j>=volume[i])
{
dp[i][j] = max(dp[i-1][j],dp[i-1][j-volume[i]]+value[i]);
if(dp[i][j]>maxNum)
maxNum = dp[i][j];
}
}
最佳调度问题
//b[]为每台机器现在所用时间 初始设置为0
//相当于遍历 每次将一个a[]放入合适的位置
int DFS(int n,int t,int a[],int b[],int k)
{
if(n==0)
return t;
int i;
int min=a[n]+b[1];
int flag=1;
for(i=2;i<=k;i++)
{
if(min>a[n]+b[i])
{
min=a[n]+b[i];
flag=i;
}
}
b[flag]=b[flag]+a[n];
t=max(t,b[flag]);
DFS(n-1,t,a,b,k);
}
运动员最佳匹配问题
#include<iostream>
using namespace std;
int n;
int Max=-1; //Max代表男女双方竞赛优势的总和的最大值
int sum=0; //sum为临时求和
int data[21][21]; //data[i][]用于存放男运动员 i 配对后的双方竞赛优势
int maxSum[21]; //储存每个男生匹配后可得到的最大双方竞赛优势
int boo[21]; 标记女运动员是否被选
void DFS(int t)
{
if(t>=n+1)
{
Max=max(Max,sum);
return ;
}
int ctn=0;
for(int i=t;i<=n;i++)
ctn=ctn+maxSum[i];
if(sum+ctn<Max)
return ;//剪枝
for(int i=1;i<=n;i++)
{
if(boo[i]==0)
{
boo[i]=1;
sum=sum+data[t][i];
DFS(t+1);//确定这个后沿着探索接下来的
boo[i]=0;
sum=sum-data[t][i];
}
}
//这后续就return了 不过void函数不用写
}
int main()
{
cin>>n;
int P[n+1][n+1];//男竞赛优势
int Q[n+1][n+1];//女竞赛优势
for(int i=1;i<n+1;i++)
for(int j=1;j<n+1;j++)
cin>>P[i][j];
for(int i=1;i<n+1;i++)
for(int j=1;j<n+1;j++)
cin>>Q[i][j];
for(int i=0;i<n+1;i++)
boo[i]=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
data[i][j]=P[i][j]*Q[j][i];
maxSum[i]=max(maxSum[i],data[i][j]);
}
}
DFS(1);//从第一个男生开始匹配
cout<<Max;
return 0;
}
n色方柱问题(PASS)
实验综合
子集合问题
void DFS(int t)
{
if(t>n || sum>M) // 不能是n-1 因为如果s[n-1]也被采用 n不能return 要判断sum==M
return;
else if(sum==M)
{
for(int i=0;i<n;i++)
{
if(visit[i]==1)
cout<<a[i]<<" ";
}
}
else
{
sum=sum+a[t];
visit[t]=1;
DFS(t+1);
sum=sum-a[t];
visit[t]=0;
DFS(t+1);
}
}
买卖股票问题
int MIN=prices[0];
int MAX=0;
for(int i=0;i<n;i++)
{
MAX=max(MAX,prices[i]-MIN);//最大值为第i-1天的最大值或者 第i天-前i天的最小价格
MIN=min(MIN,prices[i]); //这里找最小值的办法
}
cout<<MAX;
分数背包问题
for(int k=1;k<=n;k++)
{
float num=0;
while(weight<C && num<=pro[k].s) //这里应该为<=
{
Max=Max+pro[k].p;
weight++;
num++;
}
if(weight==C && num<=pro[k].s) //较为特殊的情况
break;
Max=Max-pro[k].p;
weight--;
} //注意C是与weight有关 不是price