【USACO2.3】解题报告
前言
本章主要是动态规划,但是其中几道题的方法比较多,我采用了其他的方法。
题目已经开始变难,有几道题还特别值得思考。已经达到普及水平。
USACO:http://train.usaco.org/
2.3.1.Longest Prefix
2.3.2.Cow Pedigrees
思路:
这道题还是很有难度的。
很明显是一个,但是一开始一直在往(要递归的那种)树形那方面想,后来发现不行,于是就开始推方程。
考虑到每种转移都是和第层有关的,所以就想到设表示前个节点在前层的方案数。
那么很明显,如果根节点左边有个节点,那么右边就有个节点,那么左右的方案数就相乘即可。
那么方程就是
最终答案即为
代码:
/*
ID:ssl_zyc2
TASK:nocows
LANG:C++
*/
#include <cstdio>
using namespace std;
const int N=300;
const int MOD=9901;
int n,m,f[N][N];
int main()
{
freopen("nocows.in","r",stdin);
freopen("nocows.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
f[1][i]=1;
for (int i=2;i<=n;i++)
for (int j=1;j<=m;j++)
for (int k=1;k<i;k++)
f[i][j]=(f[i][j]+f[k][j-1]*f[i-k-1][j-1])%MOD;
printf("%d\n",((f[n][m]-f[n][m-1])%MOD+MOD)%MOD);
return 0;
}
2.3.3.Zero Sum
思路:
基础深搜题。每一个位置搜索放置空格,或,然后一下就可以了。
代码:
#include <cstdio>
using namespace std;
int a[10],n;
bool check()
{
int s=0,k=0,p=1; //分别表示总和,这一部分的值和符号
for (int i=1;i<=n;i++)
if (a[i]) //不是空格
{
if (p==1) s+=k;
if (p==2) s-=k;
p=a[i]; //记录符号
k=i;
}
else k=k*10+i; //加空格
if (p==1) s+=k;
if (p==2) s-=k;
if (!s) return 1; //符合
return 0;
}
void print()
{
putchar('1');
for (int i=2;i<=n;i++)
{
if (a[i]==0) putchar(' ');
if (a[i]==1) putchar('+');
if (a[i]==2) putchar('-');
putchar(i+48);
}
printf("\n");
}
void dfs(int x)
{
if (x>n)
{
if (check()) print();
return;
}
for (int i=0;i<=2;i++) //一定要按照空格,+再到-的顺序枚举,因为要求字典序
{
a[x]=i;
dfs(x+1);
}
}
int main()
{
scanf("%d",&n);
a[1]=1; //第一位必须是+
dfs(2);
return 0;
}
2.3.4.Money Systems
完全背包模板。
QWQ
代码:
#include <cstdio>
#define ll long long
#define N 10100
#define M 30
using namespace std;
ll f[N];
int n,m,a[M];
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
f[0]=1;
for (int i=1;i<=n;i++)
for (int j=a[i];j<=m;j++)
f[j]+=f[j-a[i]];
printf("%lld\n",f[m]);
getchar();
getchar();
return 0;
}
2.3.5.Controlling Companies
思路:
这道题正解是深搜,但是暴力也是过的。
看代码吧。。。
代码:
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=110;
int m,n,x,y,z,K[N][N],sum[N],SUM;
//K[i][j]表示公司i占公司j的股份
bool q[N][N],ap[N];
struct answer
{
int x,y;
}ans[N*N];
struct node
{
int x,s;
}p[N][N];
bool cmp(answer x,answer y)
{
if (x.x<y.x) return 1;
if (x.x>y.x) return 0;
if (x.y<y.y) return 1;
return 0;
}
int main()
{
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
ap[x]=ap[y]=1;
K[x][y]=z;
p[x][++sum[x]].x=y;
p[x][sum[x]].s=z;
}
for (int i=1;i<=100;i++)
for (int l=1;l<=100;l++)
for (int j=1;j<=100;j++) //时间复杂度平摊后为n^3
if (ap[i]&&ap[j]&&i!=j&&(!q[i][j])&&K[i][j]>50)
{
q[i][j]=1;
ans[++SUM].x=i;
ans[SUM].y=j;
for (int k=1;k<=sum[j];k++)
K[i][p[j][k].x]+=p[j][k].s;
break; //break使得复杂度平摊
}
sort(ans+1,ans+1+SUM,cmp);
for (int i=1;i<=SUM;i++)
printf("%d %d\n",ans[i].x,ans[i].y);
return 0;
}