Dp&&背包_模板

1.多重背包

void zoreonepack(int val,int cost)
{
    for(int i=v;i>=cost;i--)
    {
        if(dp[i-cost]+val>dp[i])
        {
            dp[i]=dp[i-cost]+val;
        }
    }
}
void completepack(int val,int cost)
{
    for(int i=cost;i<=v;i++)
    {
        dp[i]=max(dp[i],dp[i-cost]+val);
    }
}
void multipack(int val,int cost,int num)
{
    if(num*cost>=v)
    {
        completepack(val,cost);
    }
    else
    {
        int k=1;
         while(k<num)
         {
             zoreonepack(k*val,k*cost);
             num-=k;k+=k;
         }
         zoreonepack(num*val,num*cost);
    }
}


2.O(n^2)TSP

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define INF 0x3f3f3f3f
int n,d[1005],dp[1005][1005];
int dis(int a,int b)
{
    int tmp=abs(d[a]-d[b]);
    return min(tmp,360-tmp);
}
int TSP_Dp()
{
    dp[2][1]=dis(1,2);
    for (int i = 3; i <= n + 1; i++) {
        dp[i][i-1] = INF;

        for (int j = 1; j < i-1; j++) {
            dp[i][i-1] = min(dp[i][i-1], dp[i-1][j] + dis(i, j));
            dp[i][j] = dp[i-1][j] + dis(i, i-1);
        }
    }

    int ans = INF;
    for (int i = 1; i <= n; i++)
        ans = min(ans, dp[n+1][i] + dis(n+1, i));
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        d[1]=0;
        int ans=0;
        scanf("%d",&n);
        for(int i=2;i<=n+1;i++)
        {
            int a;
            scanf("%d%d",&a,&d[i]);
            if(i==n+1)ans+=a*800;
            ans+=10;
        }
        ans+=TSP_Dp();
        printf("%d\n",ans);
    }
}

3.分组背包


        memset(dp,0,sizeof(dp));  
        for(int i=1;i<=1005;i++)  
        {  
            memset(dp2,0,sizeof(dp2));  
            for(int j=0;j<=1005;j++)dp2[j]=dp[j];  
            for(int j=0;j<mp[i].size();j++)  
            {  
                int num=mp[i][j];  
                for(int k=v;k>=a[num].cost;k--)  
                {  
                    dp2[k]=max(dp2[k],dp[k-a[num].cost]+a[num].val);  
                }  
            }  
            for(int j=0;j<=1005;j++)dp[j]=max(dp[j],dp2[j]);  
        }  
        printf("%d\n",dp[v]);  

4.在线倍增LCA


void Dfs(int u,int from)
{
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(v==from)continue;
        d[v]=d[u]+1;
        dist[v]=dist[u]+e[i].w;
        p[v][0]=u;
        Dfs(v,u);
    }
}
void init()
{
    for(int j=1;(1<<j)<=n;j++)
    {
        for(int i=1;i<=n;i++)
        {
            p[i][j]=p[p[i][j-1]][j-1];
        }
    }
}
int Lca(int x,int y)
{
    if(d[x]>d[y])swap(x,y);
    int f=d[y]-d[x];
    for(int i=0;(1<<i)<=f;i++)
    {
        if((1<<i)&f)y=p[y][i];
    }
    if(x!=y)
    {
        for(int i=(int)log2(N);i>=0;i--)
        {
            if(p[x][i]!=p[y][i])
            {
                x=p[x][i];
                y=p[y][i];
            }
        }
        x=p[x][0];
    }
    return x;
}

5.斜率优化Dp

#include<stdio.h>  
#include<string.h>  
using namespace std;  
int que[650000];  
int a[650000];  
int sum[650000];  
int dp[650000];  
int n,m;  
int A(int j,int k)  
{  
    return (dp[j]+sum[j]*sum[j])-(dp[k]+sum[k]*sum[k]);  
}  
int B(int j,int k)  
{  
    return 2*(sum[j]-sum[k]);  
}  
int Val(int i,int j)  
{  
    return dp[j]+(sum[i]-sum[j])*(sum[i]-sum[j])+m;  
}  
int main()  
{  
    while(~scanf("%d%d",&n,&m))  
    {  
        sum[0]=0;  
        memset(dp,0,sizeof(dp));  
        memset(que,0,sizeof(que));  
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);  
        for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];  
        int head=0,tot=0;  
        que[tot++]=0;  
        for(int i=1;i<=n;i++)  
        {  
            while(head+1<tot&&A(que[head+1],que[head])<=sum[i]*B(que[head+1],que[head]))head++;  
            dp[i]=Val(i,que[head]);  
            while(head+1<tot&&A(i,que[tot-1])*B(que[tot-1],que[tot-2])<=A(que[tot-1],que[tot-2])*B(i,que[tot-1]))tot--;  
            que[tot++]=i;  
        }  
        printf("%d\n",dp[n]);  
    }  
}  

单调队列

        for(int i=1; i<=n; i++)
        {
            while(s<=e&&q[s].pos<i-m+1)s++;
            while(s<=e&&q[e].val>a[i])e--;
            e++,q[e].pos=i,q[e].val=a[i];
        }

6.RMQ查询区间最大最小值

#include<stdio.h>  
#include<string.h>  
#include<cmath>  
#include<iostream>  
using namespace std;  
int n,q;  
int maxn[200005][20];  
int minn[200005][20];  
void ST()  
{  
    int len=floor(log10(double(n))/log10(double(2)));  
    for(int j=1;j<=len;j++)  
    {  
        for(int i=1;i<=n+1-(1<<j);i++)  
        {  
            maxn[i][j]=max(maxn[i][j-1],maxn[i+(1<<(j-1))][j-1]);  
            minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]);  
        }  
    }  
}  
int main()  
{  
    scanf("%d%d",&n,&q);  
    for(int i=1;i<=n;i++)  
    {  
        int tmp;  
        scanf("%d",&tmp);  
        maxn[i][0]=minn[i][0]=tmp;  
    }  
    ST();  
    for (int i = 1; i <= q; ++i){  
            int a,b;  
        scanf("%d%d", &a, &b);  
        if(a>b)swap(a, b);  
        int len= floor(log10(double(b-a+1))/log10(double(2)));  
        printf("%d\n",max(maxn[a][len], maxn[b-(1<<len)+1][len])-min(minn[a][len], minn[b-(1<<len)+1][len]));  
    }  
    return 0;  
}

7.nlogn LIS


    memset(dp,0,sizeof(dp));
    memset(f,0x7f,sizeof(f));
    for(int i = 1; i <= n; ++i)
    {
        int k = lower_bound(f + 1, f+ 1 + n, a[i]) - f;
        dp[i] = k;
        f[k] = a[i];
    }

最长递减子序列


int find(int n,int key)
{
	int left=0;
	int right=n;
	while(left<=right)
	{
		int mid=(left+right)/2;
		if(res[mid]>key)
		{
			left=mid+1;
		}
		else
		{
			right=mid-1;
		}
	}
	return left;
}

int Lis(int a[],int n)
{
	int r=0;
	res[r]=a[0];
	r++;
	for(int i=1;i<n;i++)
	{
		if(res[r-1]>a[i])
		{
			res[r]=a[i];
			r++;
		}
		else
		{
			int loc=find(r,a[i]);
			res[loc]=a[i];
		}
	}
	return r;
}

最长不递减


int Slove(int n)
{
    int c=0;
    for(int i=1; i<=n; i++)
    {
        int t=a[i];
        if(i==1) f[++c]=t;
        else
        {
            if(t>=f[c]) f[++c]=t;
            else
            {
                int pos=upper_bound(f+1,f+c,t)-f;//二分找到数组中比t大的第一个元素的的地址。
                f[pos]=t;
            }
        }
    }
    return c;
}


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值