首页 > 其他 > 详细

8.8&8.9 dp训练小结

时间:2019-08-26 21:14:50      阅读:84      评论:0      收藏:0      [点我收藏+]

写了两天的dp题,表示大多dp都不会啊,还是爆搜大法好。我真的太蒻了dp还是要多做题啊,一些基本的套路还是不熟,真正写对的dp也就一道,还一道爆搜过的,dp还有很深的坑要填啊。。

8.8

T1 质数和式

题意

技术分享图片

大概就是给出一个数n,用质数将它表示按字典序由大到小排序,输出排列为k的质数和式

解析

技术分享图片
技术分享图片

代码(咕咕)

T2 终极简单问题

技术分享图片

假的终极简单

解析

技术分享图片

挂上学长的题解

代码(继续咕咕)

T3 分宝藏

题意

技术分享图片
技术分享图片

一道比较有趣的题,等有时间写吧。

技术分享图片

技术分享图片

代码(继续吧)

T4 取数字问题

题意

技术分享图片

sb题目,不多说,爆搜就能过。

代码(这个总算没咕咕)

#include<bits/stdc++.h>
using namespace std;
int n,m,ans=1<<30,a[15][15];
void dfs(int x,int y,int data){
    if(x==n&&y==m){
        if(data>0){
            ans=min(ans,data);
            return;
        }
    }
    if(x+1<=n&&y<=m) dfs(x+1,y,data+a[x+1][y]);
    if(x<=n&&y+1<=m) dfs(x,y+1,data+a[x][y+1]);
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            scanf("%d",&a[i][j]);
        }
    }
    dfs(1,1,a[1][1]);
    if(ans==(1<<30)) printf("-1");
    else printf("%d",ans);
    return 0;
}

正解据说是这样的

技术分享图片

技术分享图片

T5 求三角形最大的面积

题意

技术分享图片
技术分享图片
技术分享图片

爆搜拿了40多分。。。

解析

技术分享图片

代码(马上就补)

8.9

T1 可怜的绵羊

题意

技术分享图片
技术分享图片
技术分享图片

一道比较神仙的题目,做法看解析吧,考场输出die个get 13 point

技术分享图片

代码(还毛写,先放std)

#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
#define maxn 101
 
struct point {
    long long x,y;
};
long long n,m=0;
//凸多边形顶点坐标和内部点的坐标
point vertex[maxn],insd[maxn];
//检查点是否在多边形边上
int out[maxn][maxn],online[maxn][maxn];
 
//默认的abs函数是对整数取绝对值
long long abs(long long x){
    return x<0 ? -x : x;
}
 
//返回三角形abc面积的两倍
long long area(point a,point b,point c){
    return abs(a.x*(b.y-c.y)+b.x*(c.y-a.y)+c.x*(a.y-b.y));
}
 
//向量oa叉乘向量ob
//大于0,这三个点是逆时针;小于0,这三个点是顺时针
long long multiple(point a,point b,point o){
    return (a.x-o.x)*(b.y-o.y)-(a.y-o.y)*(b.x-o.x);
}
 
void prepare(){
    long i,j,k,tmp;
    memset(out,0,sizeof(out));
    memset(online,0,sizeof(online));
    for (i=1;i<=n;i++)
        for (j=1;j<=n;j++)
            if (i!=j)
                for (k=1;k<=m;k++){
                    tmp=multiple(insd[k],vertex[j],vertex[i]);
                    if (tmp>=0) out[i][j]++; //判断是否在逆时针方向
                    if (tmp==0) online[i][j]=1;
                }
}
 
void dp(){
    long long u,i,j;
    long long a[maxn],tmp,max=0;
    //枚举点u,并求出最大值
    for (u=1;u<=n-2;u++){
        memset(a,0,sizeof(a));
        for (i=u+1;i<=n-1;i++)
            for (j=i+1;j<=n;j++)
                //判断三角形内是否有点
                if (out[u][i]+out[i][j]+out[j][u]==m) {
                    //更新a[j]的值,取最大值
                    tmp=area(vertex[u],vertex[i],vertex[j]);
                    if (tmp>a[j]) a[j]=tmp;
                    if (online[u][i]==0) {
                        tmp+=a[i];
                        if (tmp>a[j]) a[j]=tmp;
                    }
                }
        for (j=u+2;j<=n;j++)
            if (a[j]>max) max=a[j];
    }
    if (max==0) printf("die\n");
        else printf("%.2f\n",max/2.);
}
 
int main(){
    scanf("%lld",&n);
    long i,j,tm,s1=0,s2;
    for (i=1;i<=n;i++)
        scanf("%lld%lld",&vertex[i].x,&vertex[i].y);
    //求总面积
    for (i=2;i<n;i++)
        s1+=area(vertex[1],vertex[i],vertex[i+1]);
    scanf("%lld",&tm);
    for (i=1;i<=tm;i++){
        scanf("%lld%lld",&insd[0].x,&insd[0].y);
        s2=0;
        for (j=1;j<=n;j++)
            s2+=area(insd[0],vertex[j],vertex[j%n+1]);
        //利用面积判断点是否在多边形内部
        if (s1==s2) insd[++m]=insd[0];
    }
    prepare();
    dp();
    return 0;
}

T2 不老的传说

题意

技术分享图片
技术分享图片

类似于涂色问题,环形问题不多说,断环加倍即可,限制条件if判断就行。终于ac了一道题。。

解析

技术分享图片
技术分享图片

代码

#include<bits/stdc++.h>
using namespace std;
int n,c,p,a[410];
int f[410][410],ans=1<<30;
int main(){
    scanf("%d %d %d",&n,&c,&p);
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
        a[i+n]=a[i];
    }
    memset(f,0x3f,sizeof(f));
    for(int i=1;i<=n;++i){
        f[i][i]=f[i+n][i+n]=1;
    }
    for(int l=2;l<=n;++l){
        for(int i=1;i<=2*n-l+1;++i){
            int j=i+l-1;
            if(a[i]==a[j]&&l<=p) f[i][j]=min(f[i+1][j],f[i][j-1]);
            else {
                for(int k=i;k<j;++k){
                    f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
                }
            }
        }
    }
    for(int i=1;i<=n;++i){
        if(f[i][i+n-1]){
            ans=min(ans,f[i][i+n-1]);
        }
    }
    printf("%d",ans);
    return 0;
}
/*
5 2 3
1 2 1 2 1
*/

T3 数字游戏

题意

技术分享图片

话说考场dfs骗了30分,一开始想的距离正解差一点啊,贪心加dp就可以过的水题,真正太蒻了

解析

技术分享图片

代码

#include<bits/stdc++.h>
using namespace std;
struct node{
    int x;
    int y;
}a[210];
int m,n,k;
int f[210][210];
bool book[210];
long long ans;
bool cmp(node a,node b){
    return a.y>b.y;
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i].x);
    }
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i].y);
    }
    sort(a+1,a+1+n,cmp);
    f[0][0]=0;
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            f[i][j]=max(f[i-1][j],f[i-1][j-1]+a[i].x-a[i].y*(j-1));
        }
    }
    printf("%lld",f[n][m]);
    return 0;
}

T4 多米诺骨牌问题

题意

技术分享图片

类似于就是背包,考场竟然没想到,打了个爆搜骗了25。

解析

技术分享图片

代码

跟解析有点不一样v[i]价值,w[i]重量,s背包容积,背包转移即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5; 
int n,s,x,y,tot,ans;
int v[maxn],w[maxn],dp[maxn];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d %d",&x,&y);
        if(x>y){
            s+=x-y;
            v[i]=2*(x-y);
            w[i]=1;
        }
        else{
            s+=y-x;
            v[i]=2*(y-x);
            w[i]=-1;
            tot++;
        }
    }
    for(int i=1;i<=s;++i) dp[i]=maxn;
    dp[0]=0;
    for(int i=1;i<=n;++i){
        for(int j=s;j>=v[i];--j){
            if(dp[j-v[i]]!=maxn){
                dp[j]=min(dp[j],dp[j-v[i]]+w[i]);
            }
        }
    }
    for(int i=s;i>=0;--i){
        if(dp[i]!=maxn){
            ans=dp[i];
            break;
        }
    }
    printf("%d",ans+tot);
    return 0;
}
/*
4
6 1
1 5
1 3
1 2
*/

T5 下楼问题

题意

技术分享图片
大概就是每一楼有3个门问走到第一楼的最长时间

一道比较简单的dp题,考场看到是英文题便放弃了

技术分享图片

代码(以后再说吧)

T6 瞬移

题意

技术分享图片
技术分享图片

同上

解析

技术分享图片
技术分享图片

代码(std)

#include <stdio.h>
#include <stdlib.h>
#include <map>

const int maxn = 1000;
const int maxm = 12;

typedef std::map<std::pair<int, int>, int>::iterator Iter;
std::map<std::pair<int, int>, int> ans[maxn];
int tc, tt, n, m, ma, mi, x, y, bans;
char a[maxn][maxm];

int main ()
{
    freopen("teleportation.in", "r", stdin);
    freopen("teleportation.out", "w", stdout);
  scanf ("%d", &tc);
  for (int tt = 0; tt < tc; tt++)
  {
    scanf ("%d%d%d%d%d%d", &n, &m, &mi, &ma, &x, &y);
    for (int i = 0; i < n; i++)
    {
      scanf ("%s", a[i]);
      // printf ("%s\n", a[i]);
    }
    ans[0].clear ();
    std::pair<int, int> p = std::make_pair<int, int> (x, y);
    ans[0][p] = 0;
    for (int i = 1; i < n; i++)
    {
      ans[i].clear ();
      for (int j = 0; j < m; j++)
      {
        if (a[i][j] == '*')
        {
          for (int k = j + mi; k <= j + ma && k < m; k++)
          {
            //printf ("--%d: [%d, %d]\n", i, j, k);
            if (a[i][k] == '*')
            {
              p = std::make_pair<int, int> (j, k);
              for (Iter it = ans[i - 1].begin (); it != ans[i - 1].end (); ++it)
              {
                int c = it->second + abs (it->first.first - j) + abs (it->first.second - k);
                if (ans[i].find (p) == ans[i].end () || ans[i][p] > c)
                  ans[i][p] = c;
              }
              // printf ("%d: [%d, %d]:%d\n", i, j, k, ans[i][p]);
            }
          }
        }
      }
    }
    bans = -1;
    for (Iter it = ans[n - 1].begin (); it != ans[n - 1].end (); ++it)
    {
      if (bans == -1 || it->second < bans)
      {
        // printf ("[%d, %d]:%d\n", it->first.first, it->first.second, it->second);
        bans = it->second;
      }
    }
    printf ("%d\n", bans);
  }
  return bans >= 0;
}

T7 护士工作安排问题

题意

技术分享图片
技术分享图片

一道比较好想不好写的题目

解析

技术分享图片

代码(std)

#include<stdio.h>
#include<string.h>

const int N = 20;
const int DAY = 5;
const int PAT = 1 << DAY;

int n;
int love[N][PAT];
int req[DAY];
int memo[N][N/2+1][N/2+1][N/2+1][N/2+1][N/2+1];
int bit[PAT][DAY];
int changed[DAY];

void preprocess() {
  for (int i = 0; i < PAT; i++) {
    int k = i;
    for (int j = 0; j < DAY; j++) {
      bit[i][DAY - 1 - j] = k & 1;
      k >>= 1;
    }
  }
}
inline int getDec(int r0, int r1, int r2, int r3, int r4) {
  return (((((((r0 << 1) | r1) << 1) | r2) << 1) | r3) << 1) | r4;
}
void input() {
  scanf("%d", &n);
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < PAT; j++) {
      scanf("%d", &love[i][j]);
    }
  }
  for (int i = 0; i < DAY; i++) {
    scanf("%d", &req[i]);
  }
}
int dp(int p, int r0, int r1, int r2, int r3, int r4) {
  if (memo[p][r0][r1][r2][r3][r4] != -1) return memo[p][r0][r1][r2][r3][r4];
  if (p == 0) {
    return memo[p][r0][r1][r2][r3][r4] = love[0][getDec(changed[0] ^ r0,
        changed[1] ^ r1, changed[2] ^ r2, changed[3] ^ r3, changed[4] ^ r4)];
  }
  int ret = 0;
  for (int i = 0; i < PAT; i++) {
    int rr0 = r0 - (bit[i][0] ^ changed[0]);
    int rr1 = r1 - (bit[i][1] ^ changed[1]);
    int rr2 = r2 - (bit[i][2] ^ changed[2]);
    int rr3 = r3 - (bit[i][3] ^ changed[3]);
    int rr4 = r4 - (bit[i][4] ^ changed[4]);
    if (rr0 >= 0 && rr0 <= p && rr1 >= 0 && rr1 <= p
        && rr2 >= 0 && rr2 <= p && rr3 >= 0 && rr3 <= p
        && rr4 >= 0 && rr4 <= p) {
      int t = dp(p - 1, rr0, rr1, rr2, rr3, rr4) + love[p][i];
      if (t > ret) ret = t;
    }
  }
  return memo[p][r0][r1][r2][r3][r4] = ret;
}
void solve() {
  for (int i = 0; i < DAY; i++) {
    if (req[i] + req[i] > n) {
      req[i] = n - req[i];
      changed[i] = 1;
    } else {
      changed[i] = 0;
    }
  }
  memset(memo, -1, sizeof(memo));
  printf("%d\n", dp(n - 1, req[0], req[1], req[2], req[3], req[4]));
}
int main() {
  freopen("nurse.in", "r", stdin);
  freopen("nurse.out", "w", stdout);
  preprocess();
  int T;
  scanf("%d", &T);
  while (T--) {
    input();
    solve();
  }
  //while (1);
  return 0;
}

T8 循环小数

题意

技术分享图片
技术分享图片

给出循环节求分数表达,一道小学数学问题,考场不会写。。

解析

A=b+a(10^m-1)

B=10^(n+m)-10^n

再约分输出A,B即可。

证明自行百度

代码()

8.8&8.9 dp训练小结

原文:https://www.cnblogs.com/donkey2603089141/p/11414975.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!