写这个报告的目的是提醒自己,自己曾经爆0
很容易想到dp[时间][位置]
递归方程很简单,而我为什么没写出来呢。
想想当时我一直卡在怎么存数据哪里,递归什么都想出来了。
为什么卡在存数据哪里
智商······
最后注意一下初始化
AC代码
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int pos[100010][11];
int dp[100010][11];
const int inf = 0x3f3f3f3f;
int maxt(int x,int y)
{
if(y==0) return max(dp[x][y],dp[x][y+1]);
if(y==10) return max(dp[x][y],dp[x][y-1]);
return max(max(dp[x][y],dp[x][y+1]),dp[x][y-1]);
}
int main()
{
int n;
while(scanf("%d",&n)&&n){
memset(pos,0,sizeof(pos));
for(int i=0,x,y;i<n;i++){
scanf("%d%d",&x,&y);
pos[y][x]++;
}
memset(dp,0,sizeof(dp));
for(int i=0;i<=100000;i++) for(int j=0;j<=10;j++) dp[i][j] = -inf;
dp[0][5] = 0;
for(int i=1;i<=100000;i++){
for(int j=0;j<=10;j++){
dp[i][j] = maxt(i-1,j) + pos[i][j];
}
}
int ans = 0;
for(int i=0;i<=10;i++) ans = max(ans,dp[100000][i]);
printf("%d\n",ans);
}
return 0;
}
这道题说是简单,但是自己总是错在一些小细节上。
并且,当时第三题卡了,心情一直不好。
我觉得这个是不应该的,是个人问题。
这题我当时好好看是会做的。
就是首先BFS一遍把每个点到终点的最远距离记录下来。
然后DFS记忆化搜索时剪支就行了。
下面是代码
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
long long mp[101][101];
long long dp[101][101];
const int dx[] = {0,0,1,-1};
const int dy[] = {1,-1,0,0};
int vis[51][51];
int n;
struct po
{
int x,y,v;
friend bool operator < (const po a,const po b){
return a.v > b.v;
}
};
void bfs()
{
memset(vis,0,sizeof(vis));
po a = {n-1,n-1,mp[n-1][n-1]};
vis[n-1][n-1] = 1;
priority_queue<po> q;
q.push(a);
while(!q.empty()){
po v = q.top();q.pop();
for(int i=0;i<4;i++){
int xn = v.x + dx[i];
int yn = v.y + dy[i];
if(xn < 0 || yn < 0 || xn >=n || yn >= n) continue;
if(vis[xn][yn]) continue;
vis[xn][yn] = 1;
int vn = v.v + mp[xn][yn];
po u = {xn,yn,vn};
mp[xn][yn] = vn;
q.push(u);
}
}
}
long long dfs(long long x,long long y)
{
long long ans = 0;
if(!dp[x][y]){
for(int i=0;i<4;i++){
int xn = x + dx[i];
int yn = y + dy[i];
if(xn < 0 || yn < 0 || xn >= n || yn >=n) continue;
if(mp[xn][yn] >= mp[x][y]) continue;
ans += dfs(xn,yn);
}
dp[x][y] = ans;
}
return dp[x][y];
}
int main()
{
while(~scanf("%d",&n)){
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
scanf("%lld",&mp[i][j]);
}
}
bfs();
dp[n-1][n-1] = 1;
long long ans = dfs(0,0);
printf("%lld\n",ans);
}
return 0;
}
第三题 HDU 5410 CRB and His Birthday
这道题是我最大的失败,明明知道要把A[i] 和 B[i] 分开,但是为什么一直没想出来
首先得想出来取任何一个物品都会得到一个B
这样的话,我们就可以把A[i] + B[i]看成是一个01背包
然后再对 A[i] 进行完全背包
下面是代码
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int a[2020],b[2020],w[2020];
int dp[2020];
int main()
{
int t;
scanf("%d",&t);
while(t--){
int m,n;
scanf("%d%d",&m,&n);
for(int i=0;i<n;i++) scanf("%d%d%d",&w[i],&a[i],&b[i]);
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++){
for(int j=m;j>=w[i];j--){
dp[j] = max(dp[j-w[i]] + a[i] + b[i] ,dp[j]);
}
}
for(int i=0;i<n;i++){
for(int j=w[i];j<=m;j++){
dp[j] = max(dp[j],dp[j-w[i]] + a[i]);
}
}
printf("%d\n",dp[m]);
}
return 0;
}
第四题 CodeForces 543A Writing Code
这题主要完成一个转换,一开始定义dp[前i个程序员][写了j行代码][犯了k个错]
递推方程就知道很简单了,但是这样会错,还要优化。
仔细一看就知道可以优化成dp[写了j行代码][犯了k个错]
下面是代码
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int a[510];
int dp[510][510];
int main()
{
int n,m,b,mod;
scanf("%d%d%d%d",&n,&m,&b,&mod);
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
dp[0][0] = 1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
for(int k = a[i];k<=b;k++){
dp[j][k] += dp[j-1][k-a[i]];
dp[j][k] %= mod;
}
}
}
int ans = 0;
for(int i=0;i<=b;i++){
ans += dp[m][i] ;
ans %= mod;
}
printf("%d\n",ans);
return 0;
}
这题需要状态压缩,并且用floyd算法先算出每个点到另外一个地方的最小距离,因为你中途经过那些点答案并不需要你输出
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#define inf 0x1f1f1f1f
using namespace std;
int dp[(1<<17)][20];
int mp[20][20];
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n,m;
scanf("%d%d",&n,&m);
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++){
mp[i][i] = 0;
for(int j=1;j<=n;j++){
if(i!=j) mp[i][j] = inf;
}
}
for(int i=0,x,y,z;i<m;i++){
scanf("%d%d%d",&x,&y,&z);
if(mp[x][y]>z) mp[x][y] = mp[y][x] = z;
}
dp[1][1] = 0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++) mp[j][k] = min(mp[j][k] , mp[j][i] + mp[i][k]);
int tot = (1<<n)-1;
for(int i=1;i<=tot;i++){
for(int j=1;j<=n;j++){ // st
if(i&(1<<(j-1))){
for(int k=1;k<=n;k++){
if(k==j) continue;
if(i&(1<<(k-1))) continue;
else dp[i | (1<<(k-1))][k] = min(dp[i | (1<<(k-1))][k] , dp[i][j] + mp[j][k]);
//printf("%d\n",dp[i][k]);
}
}
}
}
int ans = inf;
for(int i=1;i<=n;i++) ans = min(ans, dp[tot][i] + mp[i][1]);
printf("%d\n",ans);
}
return 0;
}