宁波工程学院2020新生校赛

C

一开始还想什么计算几何的方法,后来才发现,直接枚举两条之间的交点就好了……

#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<utility>
#include<vector>
#include<set>
//#define int long long
using namespace std;
int n;
double k,b;
vector<pair<double,double> >v;
set<pair<double,double> >s;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%lf %lf",&k,&b);
		v.push_back(make_pair(k,b));
	}
	for(int i=0;i<v.size();i++)
	{
		for(int j=i+1;j<v.size();j++)
		{
			double kk,bb;
			kk = v[i].first - v[j].first;
            bb = -(v[i].second - v[j].second);
            if (kk == 0.0) {
                continue;
            }
            double x = bb / kk;
            double y = v[i].first * x + v[i].second;
            s.insert(make_pair(x,y));
		}
	}
	if(s.size()==0)
	{
		printf("No Fire Point.\n");
	}
	else
	{
		printf("%d",s.size());
	}
}

E

就是个二进制优化背包,当物品数量有无限的时候,直接先做一次完全背包,剩下的就是二进制拆分优化多重背包。思路就是,按二次方拆分物品,放进新的背包,然后跑一次01背包,就可以了。证明知乎有。

#pragma GCC optimize(2)
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<utility>
#include<vector>
#include<set>
#define int long long
using namespace std;
int e1,e2,s1,s2,e,n,t,q,s,v[100005*21],w[100005*21],c[100005*21],f[100005],vv,ww,cc,cnt;
signed main()//v是物品体积,w是物品价值,c是物品个数,f就是用来转移的 
{
	//ios::sync_with_stdio(false);
	scanf("%lld:%lld %lld:%lld %lld",&e1,&s1,&e2,&s2,&n);
	int sec=(e2-e1)*60+s2-s1;//这个是背包容积 
	//cout<<sec<<endl;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld %lld %lld",&vv,&ww,&cc);
		if(cc==0)
		{
			for(int j=vv;j<=sec;j++)
			{
				f[j]=max(f[j-vv]+ww,f[j]);//当物品个数无限就直接完全背包,这个是题解看来的,一开始我把物品个数弄inf,改来改去都不对 
			}
		}
		else
		{
			for(int j=1;j<=cc;j*=2)//拆分物品个数 
			{
				v[++cnt]=j*vv;
				w[cnt]=j*ww;
				cc-=j;
			}
			if(cc)
			{
				v[++cnt]=cc*vv,w[cnt]=cc*ww;
			}
		}
	}
	for(int i=1;i<=cnt;i++)
	{
		for(int j=sec;j>=v[i];j--)//01背包处理 
		{
			f[j]=max(f[j],f[j-v[i]]+w[i]);
		}
	}
	cout<<f[sec];
}

J
如果01背包要算上物品数量,那么也按普通的背包转移来就可以了。

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<utility>
#include<vector>
#include<set>
#include<queue>
using namespace std;
int t,n,s,v[10004],w[10004],f[10004],num[10004];
int main()
{
	cin>>t;
	while(t--)
	{
		memset(f,0,sizeof(f));
		memset(num,0,sizeof(num));
		scanf("%d %d",&n,&s);
		for(int i=1;i<=n;i++)
		{
			scanf("%d %d",&w[i],&v[i]);
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=s;j>=w[i];j--)
			{
				if(f[j-w[i]]+v[i]>f[j])
				{
					f[j]=f[j-w[i]]+v[i];
					num[j]=num[j-w[i]]+1;
				}
			}
		}
		printf("%d %d\n",f[s],num[s]);
	}
}

题目

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值