使用一维数组的版本:
01背包:
int main() {
int n,m;
while(cin>>n>>m) {
vector weight(n+1,0);//物品的重量
vector value(n+1,0);//物品的价值
vector dp(m+1,0);//一维数组,存放用n个产品装容量为i的背包的解
for(int i=0;i>weight[i+1]>>value[i+1];//输入
for(int i=1;i<=n;i++)
//这里是逆序
//用j>=weight[i]作为判断条件,省略了一个if语句
for(int j=m;j>=weight[i];j--) {
dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
cout<
多重背包:
多重背包是指在01背包的基础上,物品的个数有限制可以是0-n个。解决这类问题的思路是将其转化成01背包,具体的方法就是n个添加同样属性的物品就可以了。
完全背包:
只需要将上面的逆序改为顺序
for(int i=1;i<=n;i++)
//这里变成了顺序
//这里设j从weight[i]开始,省略了一个if语句
for(int j=weight[i];j<=m;j++)
dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
int partition(int a[], int l, int r) {
int x = a[l];//选择a[l]作为选定元素
int i = l;
int j = l+1;
for (; j <= r; j++)
if (a[j] < x) //如果a[j]小于x,就将它交换到前面去
swap(&a[++i], &a[j]);
swap(&a[l], &a[i]);//最终将a[l]交换到正确的位置上
return i;
}
void quick(int a[],int l,int r) {
if (l>=r) return;//如果子区间为0或1个元素,就可以结束递归调用
int i = partition(a,l,r);
quick(a,l,i-1);
quick(a,i+1,r);
}
int b[maxN]; //辅助数组
void partition(int a[],int l,int r) {
int i,j,k;
int m = (l+r)/2;
//将排好序了的两个子数组:a[1~m]和a[m+1~r]放入辅助数组b中
for (i=l;i<=r;i++) b[i]=a[i];
//i和j分别指向两个子数组的开头
i=l;
j=m+1;
k=l;
while(i<=m && j<=r) {
if (b[i]=r) return;
int m = (l+r)/2;
merge(a,l,m);
merge(a,m+1,r);
partition(a,l,r);
}
堆本质上是完全二叉树,用数组(vector)表示。首先定义一个数组,用来表示堆。
int N=0;
vector heap(100005,0);
上浮和插入操作:
void Up(int k) {
while(k>1 && heap[k/2]
下沉和删除操作:
void Down(int k) {
int j;
while(2*k<=N) {//如果没到达树底
j=2*k;
if(jheap[j])
j++;//找到子节点中较大的那个
if(heap[k]>heap[j])
break;//如果父节点比子节点都大,退出
swap(heap[k],heap[j]);
k=j;
}
}
int deleteMax() {
swap(heap[N],heap[1]);
N--;
Down(1);
return heap[N+1];
}
堆排序:
void PQsort(int a[],int l,int r) {
int k;
for (k=l;k<=r;k++) insert(a[k]);
for (k=r;k>=l;k--) a[k]=deleteMax();
}
int main() {
int n,m,s,t;//分别是节点数、边的条数、起点、终点
while(cin>>n>>m>>s>>t) {
vector> edge(n+1,vector(n+1,0));//邻接矩阵
vector dis(n+1,0);//从起点出发的最短路径
vector book(n+1,0);//某结点已经被访问过
for(int i=1;i<=n;i++)//初始化邻接矩阵
for(int j=1;j<=n;j++)
if(i!=j) edge[i][j]=INT_MAX;
int u,v,length;
for(int i=0;i>u>>v>>length;
if(length dis[index]+edge[index][i])
dis[i] = dis[index]+edge[index][i];
}
}
cout<
#include
using namespace std;
int pre[1050]; //保存节点的直接父节点
//查找x的根节点
int find(int a){
if(pre[a]!=a)
pre[a]=find(pre[a]);//路径压缩,本结点更新为根结点的子结点
return pre[a];
}
//连接两个连通块
void join(int x,int y) {
int fx=Find(x),fy=Find(y);
if(fx!=fy) pre[fy]=fx;
}
int main() {
int N,M,a,b,i,j,ans=0;
while(scanf("%d%d",&N,&M) && N) {
//初始化pre数组
for(i=1;i<=N;i++) pre[i]=i;
//根据连通情况,构建pre数组
for(i=1;i<=M;i++) {
scanf("%d%d",&a,&b);
join(a,b);
}
for(i=1;i<=N;i++)
if(pre[i]==i) ans++; //计算连通子图的个数ans
cout<
若用邻接表表示图的信息,则有:
int in[100001]={0};//记录每个节点的入度
vector > edge[100001]; //邻接表
int main() {
int n,m;//节点数和顺序关系的数量
while(cin>>n>>m) {
int from,to;
int i,k;
int index;
int cnt=0;
for(i=1;i<=m;i++) {//初始化每个节点的入度
cin>>from>>to;
edge[from].push_back(to);
in[to]++;
}
for(k=1;k<=n;k++)
{
index=0;//当前这轮确定了的节点编号
bool valid = false;
for(i=1;i<=n;i++) {
if(in[i]==0) {//若某个未确定节点的入度为0
index=i;
cnt++;
in[i]--;
valid = true;
break;
}
}
if(!valid) {//如果在未确定的节点中,找不到入度为0的
cout<<"Wrong"<
本质上,是利用匹配子串的最长公共前后缀的信息来提高效率。
void makeNext(string P,vector &next)
{
int q,k;
int m = P.size();
next[0] = 0;
for (q = 1, k = 0;q < m;q++)
{
while(k > 0 && P[q] != P[k])
k = next[k-1];
if (P[q] == P[k])
k++;
next[q] = k;
}
}
int kmp(string T,string P,vector &next) {
int n=T.size();
int m=P.size();
int i=0,q=0;
int ans=0;
for (;i < n;i++) {
while(q > 0 && P[q] != T[i])
//如果失配了,退回q-(q-next[q-1]) = next[q-1]位
q = next[q-1];
if (P[q] == T[i]) //如果当前字符匹配成功,q后移一位
q++;
if (q == m) //如果已经成功匹配一次
ans++;
}
return ans;
}
int main() {
int N;
string mo,str;
cin>>N;
while(N--) {
cin>>mo>>str;
vector next(mo.size(),0);
makeNext(mo,next);//构建部分匹配表
cout<