第三次模拟比赛(湘潭邀请赛第二次选拔赛)

G - Nested Dolls

题目意思:题目

解题思路:这是一个贪心题目,首先对h或者w按照从大到小排序,如果两个值相同,按照另一个值从小打大排序。之后两个for循环和一个vis标记即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 20000 + 20;
struct node{int w,h;}tao[N];
int vis[N];
bool cmp(const node&n1,const node&n2)///先按照宽度排序(从大到小),再按照高度排序(从小到大)
{
    if(n1.w == n2.w)    return n1.h < n2.h;
    return n1.w > n2.w;
}

int main()
{
    int t,m;
    cin >> t;
    while(t--){
        memset(vis,0,sizeof(vis));
        cin >> m;
        for(int i = 0;i < m;++ i)
            scanf("%d%d",&tao[i].w,&tao[i].h);
        sort(tao,tao + m,cmp);

        int ans = 0;
        for(int i = 0;i < m;++ i){
            if(vis[i])  continue;
            vis[i] = 1;
            int x = tao[i].w;
            int y = tao[i].h;
            ans ++;
            for(int j = 0;j < m;++ j){
                if(vis[j])  continue;
                if(x > tao[j].w && y > tao[j].h){
                    vis[j] = 1;
                    x = tao[j].w;
                    y = tao[j].h;
                }
            }
        }
        for(int i = 0;i < m;++ i)
            cout << vis[i] << ' ';
        cout << endl;

        cout << ans << endl;
    }
}
/*
4
3
20 30 40 50 30 40
4
20 30 10 10 30 20 40 50
3
10 30 20 20 30 10
4
10 10 20 30 40 50 39 51
*/

I - Moogle  

题目意思:题目意思

思路:动态规划,有一个 博客 讲的很好 

#include<iostream>
#include<cmath>
#include<iomanip>
#define INF 0x3f3f3f3f3f3
using namespace std;
const int N = 210;
int x[N];
double dp[N][N];
double sum[N][N];//sum[i][j]是以i为起点,以j为终点计算得到的区间误差和

int main()
{
    int t,h,c;
    cin >> t;
    while(t--){
        cin >> h >> c;
        for(int i = 1;i <= h;++ i)
            cin >> x[i];

        for(int i = 1;i <= h;++ i){
            for(int j = 1;j <= c;++ j){
                dp[i][j] = INF;
                sum[i][j] = 0;
            }
        }
        dp[1][1] = 0;///初始化

        for(int i = 1;i <= h;++ i){///计算区间误差和
            for(int j = i+1;j <= h;++ j){
                for(int k = i+1;k < j;++ k){
                    double tmp = x[i] + 1.0*(x[j] - x[i])*(k-i)/(j-i);
                    sum[i][j] += abs(tmp - x[k]);
                }
            }
        }

        for(int i = 2;i < h;++ i){///状态转移
            for(int j = 2;j<=c && j<=i;++ j){
                for(int k = 1;k < i;++ k)
                    dp[i][j] = min(dp[i][j],dp[k][j-1] + sum[k][i]);
            }
        }

        for(int i = 1;i < h;++ i)///加上最后的一段误差
            dp[h][c] = min(dp[h][c],sum[i][h] + dp[i][c-1]);
        cout <<setiosflags(ios::fixed);
        cout << setprecision(4) << dp[h][c]/h << endl;
    }
}
/*
2
4 3
0 9 20 40
10 4
0 10 19 30 40 90 140 190 202 210
*/

 

cout 控制精度:

cout << setiosflags(ios::fixed);

cout << setprecision(4) << .... << endl;

 

 Copying DNA

题目意思:题目

题解博客:博客

先贴标程:

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int INF = 1 << 28;
const int MAX_m = 20;
const int MAX_n = 20;

int memo[1 << MAX_n];
char S[MAX_m + 1];
char Sr[MAX_m + 1];
char T[MAX_n + 1];
int m,n;

int match(int i,int g,char* A,int e)
{
    int longest = 0;
    for(int k = 0;k < e;++ k){
        int h = 0;
        while(h < g && k + h < e && T[i+h] == A[k+h])   h++;
        longest = max(longest,h);
    }
    return longest;
}

int solve(unsigned int found)
{
    if(memo[found] != -1)   return memo[found];

    char U[MAX_n + 1];
    char Ur[MAX_n + 1];
    fill(U,U + n,0);
    fill(Ur,Ur + n,0);

    for(int i = 0;i < n;++ i)
        if(found & 1 << i)  U[i] = T[i];

    reverse_copy(U,U + n,Ur);
    int best = INF;
    int last_h = 0;
    for(int i = 0;i < n;++ i){
        int g = 0;
        while(i + g < n && (found & 1 << i + g) == 0)   ++g;
        if(g == 0){
            last_h = 0;
            continue;
        }

        int h = 0;
        h = max(h, match(i,g,S,m));
        h = max(h, match(i,g,Sr,m));
        h = max(h, match(i,g,U,n));
        h = max(h, match(i,g,Ur,n));
        if(h == 0)  return INF;
        if(h > last_h - 1){
            int newfound = found | (1 << i+h ) - 1 ^ (1 << i) - 1;
            best = min(best,1 + solve(newfound));
        }
        if(best == INF) break;
        last_h = h;
    }
    memo[found] = best;
    return best;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%s",S);
        m = strlen(S);

        reverse_copy(S,S+m,Sr);
        scanf("%s",T);
        n = strlen(T);

        fill(memo,memo + (1 << MAX_n), -1);
        memo[(1 << n) - 1] = 0;

        int s = solve(0);
        if(s == INF)    printf("impossible\n");
        else printf("%d\n",s);
    }
}

 

我终于看懂了标程!

这道题的解题思路大致如下:
把目标串看成是一个n位的全是1的二进制串。

设定一个初始状态:即全为 0 的二进制串(表示一开始是空串)

这样,从初始状态到终态共有2^n个数字,每个数字用二进制表示时,其每一位所在的二进制值若是“1",那么就表示有一个字符,”0“表示无字符。如果直接进行搜索的话,会使得同一个状态被计算多次,从而超时。

于是我们引入记忆化搜索即可。

用ans【i】表示从初始状态到数字”i "表示的二进制串,再转化为的字符串的最短操作数。

 

上面的标程,有一次下几个需要注意的东西:
1.有两个函数:

(1) fill(char【】,char【】 + lenth, x)表示把 【】-》【】+lenth 里面的值全部变成 x

(2)reverse_copy(char【】,char【】1+ lenth,newchar【】)表示把【】-》【】+lenth 的反转串赋值给 newchar【】

 

2.炫酷操作:

(1 << i+h ) - 1 ^ (1 << i) - 1

这可以将 i~i+h位变成1,其他为0

 

总结起来就是:位运算+搜索+剪枝

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值