A - Mr. Young’s Picture Permutations
#include <iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
const int N=31;
#define ll long long
int main()
{
int n,i,j,k;
int a,b,c,d,e;//分别代表第一行,第二行,。。。,第五行
int s[5];
while( cin>>n)
{
if(n==0)
break;
memset(s,0,sizeof s);
for(i=0; i<=n-1; i++)
cin>>s[i];
ll f[s[0]+1][s[1]+1][s[2]+1][s[3]+1][s[4]+1];
memset(f,0,sizeof(f));
f[0][0][0][0][0]=1;
//状态集合对应集合的划分,令最后一个同学安排在哪一排作为划分依据
for(a=0; a<=s[0]; a++)
for(b=0; b<=min(a,s[1]); b++)
for(c=0; c<=min(b,s[2]); c++)
for(d=0; d<=min(c,s[3]); d++)
for(e=0; e<=min(d,s[4]); e++)
{
//& 完全引用
ll &x=f[a][b][c][d][e];//当前f[a][b][c][d][e].要由f[a-1][b][c][d][e]转移
//转移需满足两个要求。
//1、当前位置放下的数字要小于等于当前行要求放的数字的个数
//2、放下此人后,不能大于前一行放下的人的个数
//注意,(可能)第一行人数多,k行人数少
if(a&&a-1>=b)//最后一名同学可能被安排在第一排
x+=f[a-1][b][c][d][e];
if(b&&b-1>=c)//最后一名同学可能被安排在第二排
x+=f[a][b-1][c][d][e];
if(c&&c-1>=d)//最后一名同学可能被安排在第三排
x+=f[a][b][c-1][d][e];
if(d&&d-1>=e)//最后一名同学可能被安排在第四排
x+=f[a][b][c][d-1][e];
if(e)//最后一名同学可能被安排在第五排
x+=f[a][b][c][d][e-1];
}
cout<<f[s[0]][s[1]][s[2]][s[3]][s[4]]<<endl;
}
return 0;
}
E - 传纸条
状态表示
f(x1,x2)
集合:所有第一条路线从(1,1),走到(x1,k-x1),第二条路线(1,1)走到f(x2,k-x2)的路线组成的集合
属性:
max
可以考虑:
只走一次 f(i,j)
走两次 f(x,y,x2,y2)
我们可以记录
f(k,x1,x2)//走k步,第一次走过的横坐标是x1,第二次为x2
状态计算
last 最后一步:
1、右右
2、右下
3、下右
4、下下
右右
第一条路线:(1,1)到(x1,k-1-x1);
第二条路线:(1,1)到(x2,k-1-x2);
右下
第一条路线:(1,1)到(x1,k-1-x1);
第二条路线:(1,1)到(x2-1,k-x2);
下右
第一条路线:(1,1)到(x1-1,k-x1);
第二条路线:(1,1)到(x2,k-1-x2);
下下
第一条路线:(1,1)到(x1-1,k-x1);
第二条路线:(1,1)到(x2-1,k-x2);
我们要考虑范围
1<=x1<=n;
1<=k-x1<=m;
x1<=k-1;
x1>=k-m;
max(1,k-m)<=x1<=min(k1,n);
f(k,x1,x2)=max(f(k,x1,x2),f(k-1,x1,x2))+t;
#include <iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
const int N=55;
#define ll long long
int n,m;
int w[N][N];
int f[N<<1][N][N];
int main()
{
int i,j,k;
cin>>n>>m;
for(i=1; i<=n; i++)
for(j=1; j<=m; j++)
cin>>w[i][j];
for(k=2; k<=n+m; k++)
{
for(int x1=max(1,k-m); x1<=min(k-1,n); x1++)
for(int x2=max(1,k-m); x2<=min(k-1,n); x2++)
{
int t=w[x1][k-x1];
if(x2!=x1)//走的不是重复路线,就可以把对应w值加上。
t+=w[x2][k-x2];
//这里说一下为什么题目说不能走相同路线,这里却暗涵可以走相同路线了呢?
//原因是这里的状态属性是max,走相同路线不会加权值,那么就不会是最大值,跟最大值没有任何影响
//举个不太恰当例子:
//两个集合求最大值,即使集合有重合部分,也不会影响最后的最大值
for(int a=0; a<=1; a++)
for(int b=0; b<=1; b++)
f[k][x1][x2]=max(f[k][x1][x2],f[k-1][x1-a][x2-b]+t);
}
}
printf("%d",f[m+n][n][n]);
return 0;
}