题目意思:题目
解题思路:这是一个贪心题目,首先对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
总结起来就是:位运算+搜索+剪枝