下面的题解不会给出题目所以在开头放出比赛链接传送门
本场比赛大部分都是模板题,但是任有记录的必要性
题目分析:题目说的是每一个动物都有天敌,所以对于每组数据我们只需要标记一下猎物,然后再遍历一下所有出现过的动物,如果在遍历的过程中发现有一个动物没有被标记说明他没有天敌,也就不符合题目的意思,直接输出0并返回,反之输出1,这个题目需要注意的就是输入的是字符串,所以需要仔细看题目
set做法和杭电那道产生冠军题目基本上是一个意思
set
开两个set,一个用于去存储所有出现过的动物,另一个存储猎物,并在最后判断一下,如果两个set的大小一样,也就是说所有动物的数量和有天敌的数量相等那么也就意味着,所有动物都有天敌,形成了一个环~
#include
using namespace std;
int main()
{
set<string> a, b;
string c, d;
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
cin >> c >> d;
a.insert(c);
a.insert(d);
b.insert(d);
}
if (a.size() == b.size())
puts("1");
else
puts("0");
}
map
同样是开两个map,一个用于存储,一个用于迭代器遍历去寻找没有天敌的动物,一旦找到输出0并返回,否则输出1~
#include
using namespace std;
map<string, int> ma;
map<string, int>::iterator it; //迭代器
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
string s1, s2;
cin >> s1 >> s2;
ma[s1];
ma[s2]++; //把有天敌的标记一下
}
for (it = ma.begin(); it != ma.end(); ++it)
{
if (it->second == 0)
{
putchar('0');
return 0;
}
}
putchar('1');
}
暂且一搁,还不是很懂~
AC代码
#include
using namespace std;
int n, a[25];
char b[25];
vector<string> ans;
void dfs(int dep, int val)
{
if (dep == n)
{
if (a[dep] != val)
return;
string s;
for (int i = 2; i <= n - 1; i++)
s += b[i];
ans.push_back(s);
return;
}
b[dep] = '-';
dfs(dep + 1, val - a[dep]);
b[dep] = '+';
dfs(dep + 1, val + a[dep]);
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
dfs(2, a[1]);
printf("%d\n", ans.size());
for (int i = 0; i < ans.size(); ++i)
cout << ans[i] << endl;
return 0;
}
题目大意:说是有一个人患病,然后这个病会传染,像极了今年的新冠疫情,一个人可以在多个组织,只要这个组织的人中有一个患病那么所有人都会患病,最后要升序输出所有的人员编号
AC代码
#include
using namespace std;
const int maxn = 1e5 + 10;
int pre[maxn], a[maxn];
int find(int x)
{
if (pre[x] != x)
pre[x] = find(pre[x]);
return pre[x];
}
void join(int x, int y)
{
int a = find(x);
int b = find(y);
if (a != b)
pre[a] = b;
}
int main()
{
int x, n, m, num, xx, y, cnt;
for (int i = 0; i <= maxn; ++i)
pre[i] = i;
while (~scanf("%d%d%d", &x, &n, &m))
{
cnt = 0;
for (int i = 1; i <= m; ++i)
{
scanf("%d%d", &num, &xx); //让第一个人成为父节点
for (int i = 1; i < num; ++i)
{
scanf("%d", &y);
join(xx, y);
}
}
for (int i = 0; i <= x; ++i)
if (find(n) == find(i))
a[++cnt] = i;
printf("%d", cnt);
for (int i = 1; i <= cnt; ++i)
printf(" %d", a[i]);
puts("");
}
return 0;
}
一看到这个题目我就想到了poj一道类似的题目,所以这也是一个简单的bfs模板题,只要分三种情况分别进入队列就行,然后只要找到了对应的数字就直接返回就行
AC代码
#include
using namespace std;
const int maxn = 1e5 + 10;
int m, n;
int vis[maxn];
struct node
{
int x, step;
};
int judge(int x)
{
if (x >= 0 && x < maxn && !vis[x])
return 1;
return 0;
}
int bfs(int x)
{
queue<node> q;
node s, e;
s.x = x;
s.step = 0;
q.push(s);
while (!q.empty())
{
s = q.front();
q.pop();
if (s.x == m)
return s.step;
e.x = s.x * 2;
if (judge(e.x))
{
e.step = s.step + 1;
vis[e.x] = 1;
q.push(e);
}
e.x = s.x + 1;
if (judge(e.x))
{
e.step = s.step + 1;
vis[e.x] = 1;
q.push(e);
}
e.x = s.x - 1;
if (judge(e.x))
{
e.step = s.step + 1;
vis[e.x] = 1;
q.push(e);
}
}
return -1;
}
int main()
{
scanf("%d%d", &m, &n);
printf("%d\n", bfs(n));
}
题目分析:刚刚开始,我一直以为是一个贪心,结果贪来贪去的发现自己总是过不了题,后面经由大佬点播,原来这是一个经典的01背包,知道每个物品的消耗和价值,然后求在一个固定容器里面求得价值最大,很明显是一个01背包的题目,确实,很久很久没做dp的题目了,dp是一种思维,长时间不做确实很难跟上,但是这个01背包的模板题把我给困住了,说明还是没有深刻理解dp的思想。
滚动数组
由于这个题目的范围比较大,所以建议使用滚动数组减少空间的消耗
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int dp[maxn];
struct node
{
int wi, vi;
} w[maxn];
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%d%d", &w[i].wi, &w[i].vi);
for (int i = 1; i <= n; ++i)
for (int j = m; j >= w[i].wi; --j)
dp[j] = max(dp[j], dp[j - w[i].wi] + w[i].vi);
printf("%d\n", dp[m]);
}
如果喜欢压码的同学,可以参考下面的代码,其实也差不多
滚动数组2
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int dp[maxn];
struct node
{
int wi, vi;
} w[maxn];
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
{
scanf("%d%d", &w[i].wi, &w[i].vi);
for (int j = m; j >= w[i].wi; --j)
dp[j] = max(dp[j], dp[j - w[i].wi] + w[i].vi);
}
printf("%d\n", dp[m]);
}
01背包二维数组
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
int dp[1010][maxn];
struct node
{
int wi, vi;
} w[maxn];
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%d%d", &w[i].wi, &w[i].vi);
for (int i = 1; i <= n; ++i)
for (int j = 0; j <= m; ++j)
if (j >= w[i].wi)
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i].wi] + w[i].vi);
else
dp[i][j] = dp[i - 1][j];
printf("%d\n", dp[n][m]);
}
PS:刚刚开始看到题目的时候,一种油然而生的熟悉感,这不就是一个list的模板题吗,与杭电的一道题目十分相像
方法一:数组模拟
我们用数组去模拟一遍,把每次出队列的同学用vis标记一次,代表该同学已经出了队列,周而复始,知道数组里面的元素小于三个为止
#include
using namespace std;
const int maxn = 1e5 + 10;
int vis[maxn];
vector<int> q;
int main()
{
int n, m;
scanf("%d%d", &n, &m);
int sum = n, now = 2, num = 0;
while (sum > 3)
{
for (int i = 1; i <= n; ++i)
{
if (!vis[i]) //找出没有被标记的同学
{
num++; //记录数量
if (num == now) //如果数量等于当前需要出队列的值
{
vis[i] = 1; //标记改同学已经出队列
sum--; //人数减少一个
num = 0; //继续往后遍历
}
}
}
num = 0;
now = 5 - now; //3,2反复反复遍历
}
int ans = 0;
for (int i = 1; i <= n; ++i)
{
if (!vis[i])
{
ans += i;
q.push_back(i); //放入数组
}
}
if (ans > m)
{
for (int i = 0; i < q.size(); ++i)
if (i == 0)
printf("%d", q[i]);
else
printf(" %d", q[i]);
}
else
printf("%d\n", abs(ans - m));
}
方法二:STL之List
PS:一般来说这个题目是用来锻炼list入门的题目,所以题目并不是很难,但是需要注意的细节很多。
#include
using namespace std;
int main()
{
int n, m, k = 2;
scanf("%d%d", &n, &m);
list<int> a;
list<int>::iterator it; //迭代器储存的是元素的地址
for (int i = 1; i <= n; i++)
a.push_back(i);
while (a.size() > 3)
{
int num = 1;
for (it = a.begin(); it != a.end();)
{
if (num++ % k == 0)
it = a.erase(it);
else
it++;
}
k = 5 - k;
}
int ans = 0;
for (it = a.begin(); it != a.end(); it++)
ans += *it; //加了*号代表该地址的值
if (ans > m)
{
for (it = a.begin(); it != a.end(); it++)
{
if (it != a.begin())
putchar(' ');
printf("%d", *it);
}
}
else
printf("%d\n", abs(ans - m));
return 0;
}
PS:思维题,不是很懂,先附上代码吧
#include
using namespace std;
typedef long long ll;
int main()
{
ll t, n, m;
scanf("%lld", &t);
while (t--)
{
ll ans = 0;
scanf("%lld%lld", &n, &m);
if (m & 1)
{
ans = (m + 3) * (m - 1) / 2 / 2;
ll s = n - m + 1;
ans += (s + 1) / 2;
}
else
{
ans = (m + 2) * m / 2 / 2;
ll s = n - m;
ans += (s + 1) / 2;
}
printf("%lld\n", ans);
}
return 0;
}
简单签到题
#include
using namespace std;
const int maxn = 1e5 + 10;
char c[maxn];
int main()
{
int ans;
gets(c);
ans = 0;
int lc = strlen(c);
for (int i = 0; i < lc; ++i)
{
if (c[i] == 'o' && c[i + 1] == 'r' && c[i + 2] == 'a')
++ans, i += 2;
}
if (ans)
printf("%d\n", ans);
else
puts("yare yare daze");
}
模拟退火模板题
怎么说呢,我也没搞懂模拟退火怎么模拟,也没去搞懂,感觉也是一个活生生的模板题,所以就没花什么时间去处理,主要也是感觉这一类题目很冷门,希望不会是我的错觉吧
#include
using namespace std;
const double eps = 1e-8;//终止温度
double y;
double func(double x)//计算函数值
{
return 7 * pow(x, 7.0) + 6 * pow(x, 6.0) + 2 * pow(x, 3.0) + 8 * pow(x, 2.0) - y * x;
}
double solve()
{
double T = 100;//初始温度
double delta = 0.98, x = 50.0;//降温系数,x的初始值
double now = func(x);//计算初始函数值
double ans = now;//返回值
while (T > eps)//eps是终止温度
{
int f[2] = {
1, -1};
double newx = x + f[rand() % 2] * T;
if (newx >= 0 && newx <= 100)
{
double next = func(newx);
ans = min(ans, next);
if (now - next > eps)//更新x
{
x = newx;
now = next;
}
}
T *= delta;
}
return ans;
}
int main()
{
int cas;
scanf("%d", &cas);
while (cas--)
{
scanf("%lf", &y);
printf("%.4f\n", solve());
}
}
山水一程,三生有幸,,,白茶清欢也无事,我在等风也等你~ |
---|