题目链接
a.Black Square: http://codeforces.com/contest/431/problem/A
b.Shower Line: http://codeforces.com/contest/431/problem/B
c.k-Tree http://codeforces.com/contest/431/problem/C
A【题意】(水)
顺序输入四个数,第i个数表示去掉i需要的能量。第二行输入输入一串数(1-4以内的数),求去掉这串数所需的能量。
代码:
#include<iostream>
#include<cstdio>
using namespace std;
char s[100010];
int main()
{
int A[10];
while(scanf("%d%d%d%d",&A[1],&A[2],&A[3],&A[4])!=EOF)
{
scanf("%s",s);
int sum=0;
for(int i=0;s[i]!=0;i++)
sum+=A[s[i]-'0'];
printf("%d\n",sum);
}
return 0;
}
B【题意】(水)
一列人排队洗澡,前后的两个人相互交谈产生幸福值(如果有人当前没有交谈对象,则产生幸福值为0),队首会不断去洗澡,交谈对象改变又产生幸福值。
总共有五个人,给出两两交谈产生的幸福值。求如何排列可以产生最大幸福值,输出最大幸福值。
例:
Sample test(s)
input
0 0 0 0 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0
output
32
In the first sample, the optimal arrangement of the line is 23154. In this case, the total happiness equals:
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int vis[10];
int G[10][10];
int pre[10];//记录所选的人
int dfs(int p)
{
int ans=0;
if(p>5)
{
for(int i=1;i<=5;i++)
ans+=G[pre[i]][pre[i+1]]+G[pre[i+1]][pre[i]]+G[pre[i+2]][pre[i+3]]+G[pre[i+3]][pre[i+2]];
return ans;
}
for(int i=1;i<=5;i++)
{
if(!vis[i])
{
vis[i]=1;
pre[p]=i;
ans=max(ans,dfs(p+1));
vis[i]=0;
}
}
return ans;
}
int main()
{
int i,j;
memset(vis,0,sizeof(vis));
for(i=1;i<=5;i++)
for(j=1;j<=5;j++)
scanf("%d",&G[i][j]);
int ans=0;
for(i=1;i<=5;i++)
{
vis[i]=1;
pre[1]=i;
ans=max(ans,dfs(2));
vis[i]=0;
}
printf("%d\n",ans);
return 0;
}
c【题意】
给出一个每个节点有k个儿子的树。每个节点到第i个儿子的值为i。求有多少种方法从根开始向下走,得到的总值为n(至少经过一条值不小于d的边)。
【思路】
变形的背包。dp1[N]表示所走的边的值不大于k的所有方法,dp2[N]表示所走的边的值小于k的所有方法。dp1[n]-dp2[n]即为所求。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int dp1[110],dp2[110];
const int MOD = 1000000007;
int main()
{
int n,k,d;
while(scanf("%d%d%d",&n,&k,&d)!=EOF)
{
memset(dp1,0,sizeof(dp1));
memset(dp2,0,sizeof(dp2));
dp1[0]=dp2[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=k;j++)
{
if(i>=j)
{
dp1[i]=(dp1[i]+dp1[i-j])%MOD;
if(j<d)
dp2[i]=(dp2[i]+dp2[i-j])%MOD;
}
}
}
//cout<<dp1[n]<<ends<<dp2[n]<<endl;
int ans=(dp1[n]-dp2[n]+MOD)%MOD;//由于取模会造成dp1[n]<dp2[n],所以先加一个MOD,防止为负。
printf("%d\n",ans);
}
return 0;
}
C 【小结】:对于此题的dp[] 放入的物品即使是相同的,但如果顺序不同也看做不同的方法。而一般的背包将这看做相同的方法。i,j循环次序的不同导致了dp不同的含义。