您的位置:首页 > 其它

2016.9.17测试解题报告

2016-09-18 19:20 253 查看
这套题真水。

1.引爆炸弹

问题描述:

有n个炸弹,有些炸弹牵了一根单向引线(也就是说引线只有在这一端能被炸弹点燃),只要引爆了这个炸弹,用引线连接的下一个炸弹也会爆炸。每个炸弹还有个得分,当这个炸弹被引爆后就能得到相应得分。

现在要你引爆k个炸弹,使得分最大。

输入说明:

第1行两个整数n、k。

接下来n行每行两个整数a[i]、b[i]。a[i]表示这个炸弹用引线连接的下一个炸弹,如果a[i]为0,则表示这个炸弹没连接引线。b[i]表示这个炸弹的得分。

输出说明:

仅一个数,表示最大得分。

思路:

很容易看出题目给出的是一个树状的结构。所以分析问题的时候可以把给出的单向边反过来分析。每一次都从叶节点开始向上更新,一直更新到根结点的f值(即该结点开始的链的最大权值)和g值(即最大链中该节点所连接的子节点的序号)。然后在引爆的时候,从根节点开始向下引爆(利用刚刚处理出来的变量g),遇到已经被炸的结点就直接跳过。引爆k个节点后统计答案输出(long long)。

代码:

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
struct Node
{
int num;
int pre;
int g;
long long f;
int v;
int outdge;
bool u;
Node() {pre=g=f=outdge=v=u=0;}
}a[200005];
int pos[200005];
int ans_cnt=0;
long long ans=0;
bool cmp(Node a,Node b)
{
return a.f>b.f;
}
int n,k;
//性质:如果一个点没有被选过,那么它的最优子节点链肯定没有被选过
int main()
{
freopen("bomb.in","r",stdin);
freopen("bomb.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].pre,&a[i].f);
a[i].v=a[i].f;
a[a[i].pre].outdge++;
a[i].num=i;
}
for(int i=1;i<=n;i++) if(!a[i].outdge)
{
int pos=i;
while(a[pos].pre)
{
if(a[a[pos].pre].f<a[pos].f+a[a[pos].pre].v)
{
a[a[pos].pre].f=a[pos].f+a[a[pos].pre].v;
a[a[pos].pre].g=pos;
}
pos=a[pos].pre;
}
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++) pos[a[i].num]=i;
for(int i=1;i<=n;i++) if(!a[i].u)
{
ans_cnt++;
ans+=a[i].f;
if(ans_cnt==k) break;
int po=pos[a[i].num];
while(po)
{
a[po].u=1;
po=pos[a[po].g];
}
}
printf("%I64d",ans);
fclose(stdin);
fclose(stdout);
return 0;
}


2.取石子

问题描述:

有n个石子围成一圈,每个石子都有一个权值a[i],你需要取一些石子,每个石子的得分是a[i]*d,d表示这个石子到两边被取了的石子的距离和。现在你可以取若干石子,使得分最大。

输入说明:

第1行一个整数n。

接下来n行,每行一个整数a[i]。

输出说明:

仅一个整数,表示最大得分。

思路:

由数学证明可知,得出最大解的方案只可能是拿走一个石子或者两个石子。计算即可。

代码:

#include<cstdio>
#include <iostream>
using namespace std;
int n;
long long fir=0,sec=0;
int main()//数学题
{
freopen("stone.in","r",stdin);
freopen("stone.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if(x>=fir) sec=fir,fir=x;
else if(x>sec) sec=x;
}
if(fir>(n-2)*sec) printf("%I64d",fir*(n-1));
else printf("%I64d",(fir+sec)*(n-2));
fclose(stdin);
fclose(stdout);
return 0;
}


3.化工厂装箱员

问题描述:

118号工厂是世界唯一秘密提炼锎的化工厂,由于提炼锎的难度非常高,技术不是十分完善,所以工厂生产的锎成品可能会有3种不同的纯度,A:100%,B:1%,C:0.01%,为了出售方便,必须把不同纯度的成品分开装箱,装箱员grant第1次顺序从流水线上取10个成品(如果一共不足10个,则全部取出),以后每一次把手中某种纯度的成品放进相应的箱子,然后再从流水线上顺序取一些成品,使手中保持10个成品(如果把剩下的全部取出不足10个,则全部取出),如果所有的成品都装进了箱子,那么grant的任务就完成了。

由于装箱是件非常累的事情,grant希望他能够以最少的装箱次数来完成他的任务,现在他请你编个程序帮助他。

输入说明:

第1行为n(1<=n<=100),为成品的数量

以后n行,每行为一个大写字母A,B或C,表示成品的纯度。

输出说明:

仅一行,为grant需要的最少的装箱次数。

思路:

一眼动规。设状态f[num1][num2][num3][i]为手中由num1个A,num2个B,num3个C,一共现在处理了i个产品时候的最少次数。预处理出各个区间各产品的个数可有状态转移方程:

f[numa[i+1][i+num1]][num2+numb[i+1][i+num1]][num3+numc[i+1][i+num1]][i+num1]

f[num1+numa[i+1][i+num2]][numb[i+1][i+num2]][num3+numc[i+1][i+num2]][i+num2]

f[num1+numa[i+1][i+num3]][num2+numb[i+1][i+num3]][numc[i+1][i+num3]][i+num3]

代码:

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<iostream>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n;
int num[205][205][4];
int f[25][25][25][205];
void print(int i,int num1,int num2,int num3)
{
cout<<"qudiao A "<<num[i+1][i+num1][1]<<" "<<num2+num[i+1][i+num1][2]<<" "<<num3+num[i+1][i+num1][3]<<" "<<i+num1<<" "<<f[num[i+1][i+num1][1]][num2+num[i+1][i+num1][2]][num3+num[i+1][i+num1][3]][i+num1]<<endl;
cout<<"qudiao B "<<num1+num[i+1][i+num2][1]<<" "<<num[i+1][i+num2][2]<<" "<<num3+num[i+1][i+num2][3]<<" "<<i+num2<<" "<<f[num1+num[i+1][i+num2][1]][num[i+1][i+num2][2]][num3+num[i+1][i+num2][3]][i+num2]<<endl;
cout<<"qudiao C "<<num1+num[i+1][i+num3][1]<<" "<<num2+num[i+1][i+num3][2]<<" "<<num[i+1][i+num3][3]<<" "<<i+num3<<" "<<f[num1+num[i+1][i+num3][1]][num2+num[i+1][i+num3][2]][num[i+1][i+num3][3]][i+num3]<<endl;
}
int main()
{
freopen("worker.in","r",stdin);
freopen("worker.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
char c[5];
scanf("%s",c+1);
int flag=c[1]-'A'+1;
for(int st=1;st<=i;st++)
for(int ed=200;ed>=i;ed--)
num[st][ed][flag]++;
}
/*
for(int k=1;k<=3;k++)
{
for(int i=1;i<=11;i++)
{
for(int j=1;j<=11;j++)
cout<<num[i][j][k]<<" ";
cout<<endl;
}
cout<<endl;
}*/
memset(f,56666,sizeof f);
f[num[1][10][1]][num[1][10][2]][num[1][10][3]][10]=0;
for(int i=10;i<=n+50;i++)
for(int num1=0;num1<=10;num1++)
for(int num2=0;num2<=10;num2++)
for(int num3=0;num3<=10;num3++)
if(f[num1][num2][num3][i]<10086)
{
if(num1==0 && num2==0 && num3==0)
{
printf("%d",f[num1][num2][num3][i]);
return 0;
}
//cout<<num1<<" "<<num2<<" "<<num3<<" "<<i<<" "<<f[num1][num2][num3][i]<<endl;
f[num[i+1][i+num1][1]][num2+num[i+1][i+num1][2]][num3+num[i+1][i+num1][3]][i+num1]=min(f[num[i+1][i+num1][1]][num2+num[i+1][i+num1][2]][num3+num[i+1][i+num1][3]][i+num1],f[num1][num2][num3][i]+1);
f[num1+num[i+1][i+num2][1]][num[i+1][i+num2][2]][num3+num[i+1][i+num2][3]][i+num2]=min(f[num1+num[i+1][i+num2][1]][num[i+1][i+num2][2]][num3+num[i+1][i+num2][3]][i+num2],f[num1][num2][num3][i]+1);
f[num1+num[i+1][i+num3][1]][num2+num[i+1][i+num3][2]][num[i+1][i+num3][3]][i+num3]=min(f[num1+num[i+1][i+num3][1]][num2+num[i+1][i+num3][2]][num[i+1][i+num3][3]][i+num3],f[num1][num2][num3][i]+1);
//print(i,num1,num2,num3);
}
printf("%d",f[0][0][0]
);

fclose(stdin);
fclose(stdout);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  测试