ACM暑假集训之dp

Day1

1.HDU1024


dp[i][j]:选第j个,并且分成i段的最大plus plus
当对于第i个数来说,又2种组合方法:

  • 与当前的合并: sum(l1,r1)+sum(l2,r2)+…+sum(li-1,ri-1)+[ sum( li,ri)+a[ j] ]

  • 单独成为一段:那么对于新加进来的这个数,可能会对之前维护的dp[i-1]份进行影响,所以dp[i][j]=max(dp[i-1][j-1])+a[j];

所以转移方程为:dp[i][j]=max(dp[i-1][j],dp[i-1][k]) 其中k表示为j-1之前的数
但是考虑到n=1e6,肯定要爆的
一个算法,它的优化一般是采用贪心减少计算量,或者其他方法进行判重处理
可以观察到,假如第i次,它会查找 j-1 之前的维护的数据;假如第i-1次,它会查找j-2之前的维护的数据
也就是说,dp的第二维度其实重复计算了多次,那么,我们可以降为,用另一个一维的数组来储存它的”j-1“的最大值,这里我合并成了2个一维的dp[n][2]。

代码如下:

#include<bits/stdc++.h>
using namespace std;
int cnt=0;
const int N=1e6+11;
const int inf=-10000001;
int a[N];
int n,m;
int dp[N][2];
void solve()
{
	int temp;
   memset(dp,0,sizeof(dp));
   for(int i=1;i<=m;i++)
   {
   	  temp=inf;
   	  for(int j=i;j<=n;j++)
   	  {
   	     dp[j][0]=max(dp[j-1][0],dp[j-1][1])+a[j];
		 dp[j-1][1]=temp;
		 temp=max(temp,dp[j][0]); 	
	  }
   }
   cout<<temp<<endl;	
}
int main()
{
	while(cin>>m>>n)
	{
		for(int i=1;i<=n;i++)
		    cin>>a[i];	
		solve();
		}
}

2.HDU1029

:map计数(会卡输入输出,用scanf,printf 或者 加速)
代码如下:

#include<bits/stdc++.h>
using namespace std;
map<int,int>e;
int n;
int ans;
int main()
{
	ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
	while(cin>>n)
	{
		int x;
		e.clear();
		for(int i=1;i<=n;i++)
		{
			cin>>x;
			e[x]++;
			if(e[x]>=(n+1)/2)
			  ans=x;
		}
		cout<<ans<<endl;
	}
	return 0;	
}

3.HDU1069

解:…没什么好说的
代码如下:

#include<bits/stdc++.h>
using namespace std;
struct node
{
	int x,y,z;
};
node a[300];
int cnt=0;
int n;

void push(int x,int y,int z)
{
	a[++cnt].x=x;
	a[cnt].y=y;
	a[cnt].z=z;
}
int dp[600];
bool cmp(node x1,node x2)
{
	if(x1.x==x2.x)
	  return x1.y>x2.y;
	return x1.x>x2.x;
}
int maxn;
int main()
{
	int x,y,z;
	int k=0;
	while(cin>>n && n)
	{
		k++;
		maxn=0;
		cnt=0;
		for(int i=1;i<=n;i++)
		{
			cin>>x>>y>>z;
			push(x,y,z);
			push(y,x,z);
			push(z,y,x);
			push(y,z,x);
			push(x,z,y);
			push(z,x,y);	
		} 
		sort(a+1,a+1+cnt,cmp);
		memset(dp,0,sizeof(dp));
       for(int i=1;i<=cnt;i++)
       {
       	dp[i]=a[i].z;
       	  for(int j=1;j<i;j++)
       	  {
       	  	if(a[j].x>a[i].x && a[j].y>a[i].y)
       	  	{
       	  		dp[i]=max(dp[j]+a[i].z,dp[i]);
			}
		  }
		  maxn=max(maxn,dp[i]);
	   }
	   cout<<"Case "<<k<<": maximum height = "; 
	   cout<<maxn<<endl;
	}	
}

Day2

1.HDU1087

:最大不连续子序列
代码如下:

#include<bits/stdc++.h>
using namespace std;
int n;
const int N=1011;
int a[N];
int dp[N];
int ans;
void solve()
{
	ans=0;
	for(int i=1;i<=n;i++)
	{
		dp[i]=a[i];
		for(int j=1;j<i;j++)
		{
			if(a[i]>a[j])
			{
				dp[i]=max(dp[i],dp[j]+a[i]);
			}
		}
		ans=max(dp[i],ans);
	}
	cout<<ans<<endl;
}
int main()
{
 	while(cin>>n && n)
    {
    	for(int i=1;i<=n;i++)
    	  cin>>a[i];
    	memset(dp,0,sizeof(dp));
    	solve();	
	}
 	
 } 

2.HDU1114

:完全背包

#include<bits/stdc++.h>
using namespace std;
int T,n;
const int N=10011;
const int inf=0x3f3f3f3f;
int w[N],v[N];
int m;
int ans;
int dp[N];
bool flag;
void solve()
{
	
	ans=inf;
	for(int i=1;i<=n;i++)
	{
		for(int j=w[i];j<=m;j++)
		{
			dp[j]=min(dp[j],dp[j-w[i]]+v[i]);
		}
		
	}
	if(dp[m]>=inf)
	  flag=0;
	else
      flag=1;
//	if(flag)
//      cout<<ans;
//    else
//      cout<<"imopssible";
 
}
int main()
{
	int t;
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>t;
	int x;
	while(t--)
	{
		cin>>x>>m;
		m-=x;
		cin>>n;
		memset(dp,inf,sizeof(dp));
		dp[0]=0;
		for(int i=1;i<=n;i++)
		  cin>>v[i]>>w[i];
		solve();
		if(flag)
		  cout<<"The minimum amount of money in the piggy-bank is "<<dp[m]<<".";
		else 
		  cout<<"This is impossible.";
		cout<<endl;
	}
	return 0;
}

3.HDU1176

**解:**有点像记忆化搜索
代码如下:

#include<bits/stdc++.h>
using namespace std;
int n;
const int N=100011;
int dp[N][13];
int t;
int maxn;
int e[N][13];
void solve()
{
	for(int i=t-1;i>=0;i--)
	{
		for(int j=0;j<=10;j++)
		{
			dp[i][j]+=max(dp[i+1][j],max(dp[i+1][j+1],dp[i+1][j-1]));
		}
    } 
    cout<<dp[0][5]<<endl;
}
int main()
{
	int x,y;
	ios::sync_with_stdio(false);
	cin.tie(0);
while(cin>>n && n)
{
	t=0;
	maxn=0;
	memset(dp,0,sizeof(dp));
	memset(e,0,sizeof(e));
	for(int i=1;i<=n;i++)
	{
	  cin>>x>>y;
	  t=max(t,y);
	  dp[y][x]++;
	}
	solve();
}	
	return 0;
}

mood:
请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dai _ tu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值