一大波水题正在来袭
P1014 旅行商简化版
一道卡精度的坑爹题
做法很裸。我们将此题看作一道类似于方格取数的双进程的dp。容易考虑到,如果由(i,j)跳至(i,j+2),那么未跳的那个进程必须经过(j+1,x),否则不满足定义。我们通过这个性质定义一部分的方程。同时,通过这个方法,我们可以保证,1~min(i,j)这一段一定已经取得最小值,而对于一个最优化的路径,一定满足这个情况,也就是我们找到了一个最优子结构。
#include <stdio.h>
#include <algorithm>
#include <utility>
#include <math.h>
#include <iostream>
using namespace std;
#define x first
#define y second
double dis[1001][1001];
pair < double , double > p[1001];
double dp[1001][1001]; //表示每次到了哪两个点
int N;
double EucDis( int a , int b )
{
return sqrt((p[a].x-p[b].x)*(p[a].x-p[b].x)+(p[a].y-p[b].y)*(p[a].y-p[b].y));
}
int main()
{
scanf("%d",&N);
for ( int i=1;i<=N;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
sort(p+1,p+1+N);
for ( int i=1;i<=N;i++)
for ( int j=i+1;j<=N;j++)
dis[i][j]=EucDis(i,j);
for ( int i=1;i<=N;i++)
for ( int j=1;j<=N;j++)
dp[i][j]=1e24;
dp[2][1]=dis[1][2];
for ( int i=3;i<=N;i++)
for ( int j=1;j<i;j++)
{
if(j<i-1)
dp[i][j]=dp[i-1][j]+dis[i-1][i];
else
{
for ( int k=1;k<j;k++)
dp[i][j]=min(dp[i][j],dp[j][k]+dis[k][i]);
}
}
printf("%.2lf\n",dp[N][N-1]+dis[N-1][N]);
return 0;
}
P1117 数的划分
NOIP2001
组合计数的经典例题。我们定义状态为dp[i][j],其中第一维是当前的数字的数值,第二维是加了多少个符号。那么有两种可能,即:没有任何划分部分为一,此时的可能数等于dp[i-j][j],可以形象的看作为i-j划分为{a1-1,a2-1,a3-1,….,aj-1}的方案数等于i划分为{a1,a2,a3,….,aj}。如果有任意部分为一,那么无论它是否还有一,dp[i-1][j-1]为此时的可能性。对此求和即可。
#include <iostream>
#include <cstring>
using namespace std;
int N,K;
int dp[201][7];
int main()
{
memset(dp,0,sizeof(dp));
cin >> N >> K;
dp[0][0]=1;
for ( int i=1;i<=N;i++)
for ( int j=1;j<=K;j++)
if(i>=j)
dp[i][j]=dp[i-j][j]+dp[i-1][j-1];
cout << dp[N][K] << endl;;
}
P1057 盖房子
一道前缀和相关题,不知道为什么分类在DP下。
做法很简明。我们定义
dp[i][j]
为以
(i,j)
为矩形右下顶点的坐标。如果这点可以盖房子,那么我们只需要讨论:
1、
dp[i−1][j−1]
外推到
dp[i][j]
,即直接以原情况外推。
2、
dp[i][j−1]
与
dp[i−1][j−1]
二者较小的那个(因为瑕疵可能并不是包括在两个矩形共同覆盖的区域里的)。
那么方程易推得。这道题其实并不需要存地图,然而存了也无所谓。
#include <stdio.h>
#include <string.h>
#define min(a,b) ((a)<(b)?a:b)
#define max(a,b) ((a)<(b)?b:a)
int map[1001][1001],f[1001][1001];
int main()
{
int N,M;
scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
scanf("%d",&map[i][j]);
memset(f,0,sizeof(f));
int Ans=-1;
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
if(map[i][j])
Ans=max(Ans,f[i][j]=min(f[i-1][j-1],min(f[i-1][j],f[i][j-1]))+1);
printf("%d\n",Ans);
return 0;
}