前言
本章主要考的是贪心和一些比较麻烦的模拟。难度相比上一章有很明显的提升。但是稍微想一下还是可以想出来的(第五题除外,看了一下题解的思路)。
USACO:http://train.usaco.org
1.4.2.Mixing Milk
思路:
很明显是一道贪心基础题。肯定是要先买每单位价钱最便宜的,然后再依次买贵的。这个不用证明了吧。。。
代码:
/*
ID:ssl_zyc2
TASK:milk
LANG:C++
*/
#include <cstdio>
#include <algorithm>
#define N 5100
using namespace std;
int n,m,ans;
struct node
{
int p,d;
}a[N];
bool cmp(node x,node y)
{
return x.p<y.p;
}
int main()
{
freopen("milk.in","r",stdin);
freopen("milk.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
scanf("%d%d",&a[i].p,&a[i].d);
sort(a+1,a+1+m,cmp); //以价格排序
for (int i=1;i<=m;i++)
if (a[i].d<n) //可以全部买完
{
n-=a[i].d; //全部买完
ans=ans+a[i].d*a[i].p;
}
else
{
ans=ans+a[i].p*n; //将不够的部分买完
break;
}
printf("%d\n",ans);
return 0;
}
1.4.3.Barn Repair
思路:
首先假设买一块长度为第个牛棚第个牛棚的木板,然后我们可以试着把这块木板分成块(也就是切割次!),那么最优的肯定是先将两个牛棚之间距离最大的部分割掉,然后割掉第二大的。。。以此类推。
要特判可用木板数牛棚数的情况。
代码:
/*
ID:ssl_zyc2
TASK:barn1
LANG:C++
*/
#include <cstdio>
#include <algorithm>
#define N 250
using namespace std;
int n,m,k,a[N],b[N],sum;
bool cmp(int x,int y)
{
return x>y;
}
int main()
{
freopen("barn1.in","r",stdin);
freopen("barn1.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
if (n>=k)
{
printf("%d\n",k);
return 0;
}
for (int i=1;i<=k;i++)
scanf("%d",&a[i]);
sort(a+1,a+1+k);
sum=a[k]-a[1]+1; //一块木板
for (int i=1;i<k;i++)
b[i]=a[i+1]-a[i]; //求出任意两个相邻的牛棚之间的距离
sort(b+1,b+k,cmp);
for (int i=1;i<n;i++) //只能切n-1次!!!
sum=sum-b[i]+1;
printf("%d\n",sum);
return 0;
}
1.4.5.Prime Cryptarithm
思路:
由于每一个只可能是到中的任意一个数字,那么我们可以枚举乘数里面的五个分别是多少,然后就可以推出中间的六个的值和答案的四个的值。那么久判断每一个值是否合法即可。
时间复杂度:
代码:
/*
ID:ssl_zyc2
TASK:crypt1
LANG:C++
*/
#include <cstdio>
#include <iostream>
using namespace std;
int n,a,b,ans;
bool p[11];
bool check(int x,int y)
{
y++;
while (x)
{
if (!p[x%10]) return 0;
x/=10;
y--;
if (!y) return 0;
}
return 1;
}
int main()
{
freopen("crypt1.in","r",stdin);
freopen("crypt1.out","w",stdout);
cin>>n;
int x;
for (int i=1;i<=n;i++)
{
cin>>x;
p[x]=1;
}
for (int i=1;i<=9;i++)
if (p[i])
for (int j=0;j<=9;j++)
if (p[j])
for (int k=0;k<=9;k++)
if (p[k])
for (int l=1;l<=9;l++)
if (p[l])
for (int q=0;q<=9;q++) //枚举5个*
if (p[q])
if (check((i*100+j*10+k)*l,3))
if (check((i*100+j*10+k)*q,3)) //判断中间的六个*
if (check((i*100+j*10+k)*(l*10+q),4)) //判断积中的四个*
ans++;
printf("%d\n",ans);
return 0;
}
1.4.6.Combination Lock
思路:
暴力模拟。很简单吧。。。
小心数组越界。
代码:
/*
ID:ssl_zyc2
TASK:combo
LANG:C++
*/
#include <cstdio>
#define N 120
using namespace std;
int n,sum,a,b,c,d,e,f;
bool p[N][N][N];
int main()
{
freopen("combo.in","r",stdin);
freopen("combo.out","w",stdout);
scanf("%d%d%d%d%d%d%d",&n,&a,&b,&c,&d,&e,&f);
for (int i=a-2;i<=a+2;i++)
for (int j=b-2;j<=b+2;j++)
for (int k=c-2;k<=c+2;k++) //第一个密码
if (!p[(i+n-1)%n+1][(j+n-1)%n+1][(k+n-1)%n+1])
{
p[(i+n-1)%n+1][(j+n-1)%n+1][(k+n-1)%n+1]=1;
sum++;
}
for (int i=d-2;i<=d+2;i++)
for (int j=e-2;j<=e+2;j++)
for (int k=f-2;k<=f+2;k++) //第二个密码
if (!p[(i+n-1)%n+1][(j+n-1)%n+1][(k+n-1)%n+1])
{
p[(i+n-1)%n+1][(j+n-1)%n+1][(k+n-1)%n+1]=1;
sum++;
}
printf("%d\n",sum);
return 0;
}
1.4.7.Wormholes
思路:
有点难度啊。
由于贝西只能往下走,那么她所在位置的下面第一个虫洞就是会被传走的地方。
那么设表示在下面的第一个虫洞(坐标要相同,坐标严格小于且最近)。然后就深搜,搜出配对的方案后就判断是否成立。成立就记录。
代码:
/*
ID:ssl_zyc2
TASK:wormhole
LANG:C++
*/
#include <cstdio>
using namespace std;
int f[15],next[15],n;
int check()
{
for (int i=1;i<=n;i++)
{
int u=i;
for (int j=1;j<=n;j++)
u=next[f[u]]; //是否死循环
if (u) return 1;
}
return 0;
}
int dfs(int s)
{
if (s==n/2) return check(); //搜好了
int x;
for (x=1;x<=n;x++)
if (!f[x]) break; //没有配对
int ans=0;
for (int i=1;i<=n;i++)
if (i!=x&&!f[i])
{
f[x]=i;
f[i]=x;
ans+=dfs(s+1);
f[x]=0;
f[i]=0;
}
return ans;
}
int main()
{
freopen("wormhole.in","r",stdin);
freopen("wormhole.out","w",stdout);
scanf("%d",&n);
int x[15],y[15];
for (int i=1;i<=n;i++)
scanf("%d%d",&x[i],&y[i]);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i!=j)
if (y[i]==y[j]&&x[j]>x[i]&&(!next[i]||x[next[i]]>x[j]))
next[i]=j;
printf("%d\n",dfs(0));
return 0;
}
1.4.8.Ski Course Design
思路:
由于山峰高度只有,那么就可以枚举山峰最矮高度,然后再枚举每个山峰,如果不够或高出那么就计算所需费用。然后将所有费用取最小值即可。
代码:
/*
ID:ssl_zyc2
TASK:skidesign
LANG:C++
*/
#include <cstdio>
#include <algorithm>
#define N 1010
using namespace std;
int h[N],sum,n,ans;
int main()
{
freopen("skidesign.in","r",stdin);
freopen("skidesign.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&h[i]);
sort(h+1,h+1+n);
if (h[n]-h[1]<=17) //特判,本来就不用
{
printf("0\n");
return 0;
}
ans=1e9;
for (int i=h[1];i<=h[n]-17;i++) //枚举最低高度
{
sum=0;
for (int j=1;j<=n;j++) //枚举山峰
if (h[j]<i) sum=sum+(i-h[j])*(i-h[j]);
else if (h[j]>i+17) sum=sum+(h[j]-i-17)*(h[j]-i-17);
if (sum<ans) ans=sum;
}
printf("%d\n",ans);
return 0;
}