重现赛地址: 牛客
总共十三道题,A了七道题,罚时是同题数的榜首,惨痛银牌,再多一道就有金
了,悔しい,来年冲冲冲
剩下五道题不一定有题解(菜的不行),先从简单的开始:
M题:比赛!
题意:
首先输入一个 n ,之后 n 行给出 n 条信息,每条信息格式固定。如图,三个字符加一个用来分隔的 “ : ” ,每种字符代表一位选手,意思是第一位选手成绩排在第二位和第三位之间。根据选手给出的信息,将选手根据成绩进行一个可能的排序,能排出任意一种可能就输出序列,如果无论如何都不可能就输出No Answer。
当初看题看到关系网第一时间就往食物链方向卡了…然后又转链表map暴力,怎么都做不到完美记录下可能的输出状态。结果这是到图论拓扑题,属于是 开眼界 太菜了 (但凡当时刷点图论也不至此)
#include<bits/stdc++.h>
#include<unordered_map>
#define mem(a,b) memset(a,b,sizeof a)
#define ios_sync (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define sca scanf
#define pri printf
#define ul u << 1
#define ur u << 1 | 1
#include<vector>
#include<string>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
//最根本的操作:对于每一条信息给的三个选手,建一条有向链
//比如对 A :BC ,建 B -> A -> C
//这样就记录下来了三个选手之间的关系
//同时每建一条边都去进行一个判定,比如 B -> A ,就去判定一下从 A 开始能不能走到 B 点,如果能走到就相当于存在一个环,代表给出的信息肯定是有矛盾的,这样最后肯定找不出一条序列满足所有信息
//如果信息全部都没有矛盾,相当于这个图里没有环的存在
//一个没有环的图,非常理所当然地就应该想到拓扑序列
//
//B -> A ,A 的入度就该++,意味着 A 入队前应该先处理掉之前对其有影响的点(B),当它处理完影响自己的点后,此时输出肯定能满足所有采访(限制条件信息)
//素晴らしい
const int N = 505, M = 1005;
ll INF = 0x3f3f3f3f, mod = 1e9;
int n, m, k, T;
int h[N], ne[M], e[M], idx;//用一个邻接表,可能会有疑问重边该怎么处理?事实上重边也不影响,入度照常++就行,拓扑遍历某个点必定会把连向它的所有点(即使重复相连,这条边也肯定记录在表中)的入度--,所以不会有影响
int dist[N], ru[N], ss[N];
//ss记录离散后的数字对应的字符,毕竟最后还要输出
bool st[N];
map<char, int> mp;//离散,把选手编号转化成数字
char str[10];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
ru[b]++;//建边,单向,入度++
}
bool dfs(int a, int b) {
//判断有没有边 a -> b
mem(st, 0);
queue<int> q;
q.push(a);
st[a] = true;//从该点开始往下跑一遍图,标记点防止跑重边
while (q.size())
{
int t = q.front();
q.pop();
for (int i = h[t]; ~i; i = ne[i]) {
int j = e[i];
if (!st[j]) {
if (j == b)return true;//找的到 b
st[j] = true;
q.push(j);
}
}
}
return false;//找不到 b
}
void top_sort() {
queue<int> q;
for (int i = 1; i <= k; i++)
if (!ru[i])q.push(i);//入度0点先入队
while (q.size())
{
int t = q.front();
q.pop();
pri("%c", ss[t]);//随时输出拓扑序
for (int i = h[t]; ~i; i = ne[i]) {
int j = e[i];
ru[j]--;
if (!ru[j])
q.push(j);
}
}
}
int main() {
sca("%d", &n);
mem(h, -1);//初始化
bool flag = true;//记录信息是否有矛盾
while (n--)
{
cin.ignore(1024, '\n');//清空缓冲区
sca("%s", str);
if (!flag)continue;//如果有矛盾之后的建图都不需要了
int x = str[0], y = str[2], z = str[3];
if (!mp[x])mp[x] = ++k, ss[k] = x;//离散化,记录
if (!mp[y])mp[y] = ++k, ss[k] = y;
if (!mp[z])mp[z] = ++k, ss[k] = z;
add(mp[y], mp[x]);//传入离散后的数字建边
if (flag && dfs(mp[x], mp[y]))flag = false;
//若无矛盾,查询能否反向走到,能就有自环,矛盾
add(mp[x], mp[z]);
if (flag && dfs(mp[z], mp[x]))flag = false;
}
if (flag)
top_sort();
else pri("No Answer");
return 0;
}
看能力更新(