导语
日常
涉及的知识点
贪心,思维,搜索,拓扑
链接:Codeforces Round #743 (Div. 2)
题目
A Countdown
题目大意:略
思路:直接把每一位交换到最后一位即可,特判最后一位是否为0,如果不为0就先把最后一位清0
代码
#include <bits/stdc++.h>
using namespace std;
int t,n,a[121];
int main() {
scanf("%d",&t);
while(t--) {
scanf("%d",&n);
int sum=0,ans=0;
for(int i=1; i<=n; i++) {
scanf("%1d",&a[i]);
sum+=a[i];
if(a[i])ans++;
}
if(a[n])sum+=ans-1;
else sum+=ans;
printf("%d\n",sum);
}
return 0;
}
B Swaps
题目大意:给出一个数n,两个序列a和b,a是1-2n内所有的奇数,b是所有的偶数,现在定义一种操作如下:选择一个序列,交换第i项和第i+1项的位置,现在要求使用最少的操作次数使得a序列的字典序小于b的字典序,输出最少的操作次数
思路:a和b的数字各不相同,所以满足第一位即可,贪心的去考虑,对于a序列,如果把a[i]移动到第一位,那么就需要i-1次操作,之后找到b序列中首个数值大于a[i]的值移动到b[1]即可,假设这个数的位置为j,那么操作次数便是i+j-2,那么直接遍历原数组,计算出每个数移动到第一位的操作次数,随后对每个奇数计算出最优的偶数,选取最优解即可
代码
#include <bits/stdc++.h>
using namespace std;
int t,n,mp[212121];
const int inf=0x3f3f3f3f;
int main() {
scanf("%d",&t);
while(t--) {
scanf("%d",&n);
int res=0,ans=0;
for(int j=0; j<2; j++)//记录位置
for(int i=0; i<n; i++) {
int x;
scanf("%d",&x);
mp[x]=i;
}
ans=res=inf;//初始化
for(int i=2*n; i>=1; i--)
if(i&1)ans=min(ans,mp[i]+res);//如果是奇数
else res=min(res,mp[i]);//更新首个大于当前奇数的最优偶数位置
printf("%d\n",ans);
}
return 0;
}
C Book
题目大意:一本书,有n个章节,章节之间的阅读有拓扑关系,每次阅读遍历从1开始遍历n个章节,询问是否能读完全部章节,输出次数或-1
思路:是一个有偏向的拓扑排序,需要优先遍历编号小且入度为0的节点,在遍历过程中,如果下一个节点编号比当前节点大,代表在这次阅读过程中下一个节点可以被阅读,否则就需要增加阅读次数,以这个策略BFS图,获得最大的阅读次数,每次对能访问到的点需要减去其相邻点的入度,具体看代码
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int t,n,head[maxn],in[maxn],cnt;
typedef pair<int,int>pr;
const int inf=0x3f3f3f3f;
struct node {
int next,to;
} e[maxn];
void Add(int from,int to) {//链式前向星建图
e[++cnt].next=head[from];
e[cnt].to=to;
head[from]=cnt;
in[to]++;
}
priority_queue<pr,vector<pr>,greater<pr>>q;
int main() {
scanf("%d",&t);
while(t--) {
scanf("%d",&n);
int ans=0,res=0;
for(int i=1; i<=n; i++) {//建有向图
int k;
scanf("%d",&k);
while(k--) {
int x;
scanf("%d",&x);
Add(x,i);
}
}
for(int i=1; i<=n; i++)
if(in[i]==0)q.push({1,i});
while(!q.empty()) {
auto u=q.top();
q.pop();
ans=u.first,res++;
for(int i=head[u.second]; i; i=e[i].next) {
int v=e[i].to;
in[v]--;
if(!in[v]) {
if(v<u.second)q.push({u.first+1,v});
else q.push({u.first,v});
}
}
}
if(res==n)printf("%d\n",ans);
else printf("-1\n");
memset(in,0,sizeof(int)*(n+1));
memset(head,0,sizeof(int)*(n+1));
while(!q.empty())q.pop();
cnt=0;
}
return 0;
}
另一种实现
#include <iostream>
#include <queue>
#include <stack>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn = 2e5 + 7;
int head[maxn], nxt[maxn], ver[maxn];
int tot;
int n;
int in[maxn], dep[maxn];
void init(){
memset(head, 0, sizeof (head));
memset(in, 0, sizeof (in));
memset(dep, 0, sizeof(dep));
tot = 0;
}
void adde(int u, int v){
++tot; ver[tot] = v; nxt[tot] = head[u]; head[u] = tot;
}
int topsort(){
queue <int> q;
for (int i=1; i<=n; i++)
if (!in[i]) q.push(i), dep[i] = 1;
int ans = 0;
while (!q.empty()){
int h = q.front(); q.pop();
ans = max(ans, dep[h]);
for (int i=head[h]; i; i=nxt[i]){
int v = ver[i];
if (v < h) dep[v] = max(dep[h]+1, dep[v]);
else dep[v] = max(dep[h], dep[v]);
in[v] --;
if (!in[v]) q.push(v);
}
}
for (int i=1; i<=n; i++){
if (in[i]){
ans = -1;
break;
}
// cout << "in: " << in[i] << " dep: " << dep[i] << endl;
}
return ans;
}
int main(){
int t; scanf("%d", &t);
while (t --){
init();
scanf("%d", &n);
for (int i=1; i<=n; i++){
int k; scanf("%d", &k);
while (k --){
int v; scanf("%d", &v);
adde(v, i);
in[i] ++;
}
}
int ans = topsort();
// printf("!!!!! ");
printf("%d\n", ans);
}
return 0;
}