linux/macOS下的vim界面配置以topo_sort
Apare_xzc 2021.2.3
先说一下,一般macOS 的/usr/share/vim/vimrc 这个路径下的vimrc 不可修改readonly, 用我尝试用sudo也不可以,可能处于安全性的考虑。
我们可以在 home目录下创建 .vimrc
比如: vim ~/.vimrc
然后进入insert模式,写入一些常用的配置,然后esc :x 保存退出
- 我是在我的腾讯云服务器的ubuntu系统上面进行配置的。
首先我们可以查询一下ubuntu服务器信息:lsb_release -a
我们可以看到系统的版本号是18.04.4,用户名为Ununtu(默认的)
同时我们可以发现,服务器的终端是黑底白字,十分单调~
我们可以试一试vim的界面长什么样子:
vim topo_sort.cpp
打开之后的vim界面是这个样子的(还是黑底白字):
相信大家可以看出来,这是一个简单的对DAG拓扑排序的cpp程序,而且编码风格比较规范,不过这不是重点,我们要改造一下vim的界面才好。
vim的全局配置一般在/etc/vim/vimrc
这个路径
我们可以在ubuntu终端输入命令
cd /etc/vim
然后
vim vimrc
没错,这个/etc/vim/vimrc
是配置vim的文件,我们可以用vim打开它,然后对其进行编辑(^_^)
我们发现,最后一行现实这个文件是readonly只读的。可能是我们当前是普通用户没有权限。(刚进来是命令模式)我们在vim中输入
:q!
强行先推出。
然后在终端输入su,然后输入密码即可切换到root身份
su
输入su之后会要求输入root用户的密码(还没设置过的可以先输入sudo passwd
设置一下密码),密码不回显。
我们可以发现,终端的命令提示符最后一个字母为#
,而不是$
,说明我们已经进入了root。
然后我们可以重新编辑vimrc这个配置文件:
cd /etc/vim
vim vimrc
我们可以发现,现在就不是只读了。我们可以按下键盘上的i(或者a或者o)进入输入模式(insert mode)对配置文件进行编辑。
我们可以简单看一下原来被注释了的配置。后面有英文的解释,告诉我们某个命令是干什么用的。比如这一行:
"set showmatch " Show matching brackets.
就是告诉我们用set showmath 可以显示匹配的括号。当光标在某个括号上的时候,匹配的另一个括号会高亮显示。
我们只需要删除这一行第一个“注释就可以了。
我向virmc配置文件中加入了如下的配置:
set showcmd " 命令模式下,在底部显示,当前键入的指
set mouse=a " 支持使用鼠标
set encoding=utf-8
set t_Co=256 " 开启256色
set autoindent " 按下回车键后,下一行的缩进会自动跟上一行的缩进保持一致
set tabstop=4 " Tab键的空格数
set expandtab " Tab自动转化为空格
set softtabstop=4 " Tab转化为多少个空格
set number " 显示行号
" set cursorline " 光标所在当前行高亮
set showmatch " 光标在括号上时,自动高亮对应匹配的括号
set hlsearch " 搜索时高亮显示匹配结果
加入配置后,按下esc 回到命令模式,输入:wq退出。
然后再次用vim 打开一个文件,我们期待会变成好看的样子:
还是黑白的,不过至少显示了行号,而且tab键会自动变成4个空格。这个腾讯云服务器我也不知道咋搞的。。。
来看看我另一个虚拟机同样方法配置后的vim界面:
这个其实是在MacOS的终端,用relay登陆ubuntu虚拟机后,配置的vim的效果。
反正显示行号,和tab转4空格,showmatch的功能是可以正常显示了。至于语法高亮嘛…还得再研究。
另外,我的腾讯云服务器中ls和命令提示符都是白色,需要配置一下。
首先,我们可以在 $HOME下查看.bash_profile, 这个是一个用户的配置文件,每次登陆时候自动加载。默认的shell解释器是bash
cd ~
vim .bash_profile
cat .bash_profile
if [ -f "$HOME/.bashrc" ];then
. "$HOME/.bashrc"
#echo "已经成功加载~/.bashrc文件"
fi
感觉 . “$HOME/.bashrc” 的.也可以换成source命令, $HOME也可以写成~.
然后我们编辑 $HOME/.bashrc
可以参照这篇https://www.cnblogs.com/Q–T/p/5394993.html
alias ls='ls --color'
alias ll='ls -l --color'
PS1="\[\e[37;40m\][\[\e[32;40m\]\u\[\e[37;40m\]@\h \[\e[36;40m\]\w\[\e[0m\]]\\$ "
alias 用于定义命令别名
PS1是一个环境变量,设置命令提示符的格式。
推荐这个网站:http://bashrcgenerator.com/
PS1="\n\[$(tput sgr0)\]\[\033[38;5;11m\]\\$\[$(tput sgr0)\] \[$(tput sgr0)\]\[\033[38;5;51m\]\u\[$(tput sgr0)\] \[$(tput sgr0)\]\[\033[38;5;253m\]@\[$(tput sgr0)\] \[$(tput sgr0)\]\[\033[38;5;2m\]\H\[$(tput sgr0)\] \[$(tput sgr0)\]\[\033[38;5;226m\]\w\[$(tput sgr0)\] \[$(tput sgr0)\]\[\033[38;5;250m\][\t]\[$(tput sgr0)\]\n\[$(tput sgr0)\]\[\033[38;5;196m\]\\$\[$(tput sgr0)\] \[$(tput sgr0)\]"
上面是我用这个网站设计的仿照oh-my-zsh ys主题的PS1
效果如下
vim基本配置大概就是这个流程了。
下面简单贴一下上面截图的代码好了
#include <cstdio>
#include <vector>
#include <queue>
class Graph {
public:
Graph(int n) {
this->_node_count = n;
this->_adjanency_list.resize(n+1);
this->_indegree.resize(n+1);
}
void add_edge(int u,int v,int d) {
_adjanency_list[u].push_back(Node(v,d));
_indegree[v] += 1;
}
std::vector<int> get_distance(int source_node) {
std::vector<int> min_distance(_node_count+1,-1);
std::queue<int> Q;
min_distance[source_node] = 0;
for (int u = 1; u <= _node_count; ++u) {
if (_indegree[u] == 0) {
Q.push(u);
}
}
while (!Q.empty()) {
int tp_node = Q.front();
Q.pop();
int cur_node_dis = min_distance[tp_node];
for (int i = 0; i < (int)_adjanency_list[tp_node].size(); ++i) {
int v_node = _adjanency_list[tp_node][i].v_node;
int edge_weight = _adjanency_list[tp_node][i].edge_weight;
if (--_indegree[v_node] == 0) {
Q.push(v_node);
}
if (cur_node_dis != -1) {
if (min_distance[v_node] == -1 || (cur_node_dis + edge_weight < min_distance[v_node])) {
min_distance[v_node] = cur_node_dis + edge_weight;
}
}
}
}
return min_distance;
}
private:
struct Node {
int v_node;
int edge_weight;
Node(int v,int d) : v_node(v), edge_weight(d) {}
Node() : v_node(0), edge_weight(0) {}
};
int _node_count;
std::vector<std::vector<Node> > _adjanency_list;
std::vector<int> _indegree;
};
int main(void) {
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
int n,m,k,u,v,d;
scanf("%d%d",&n,&m);
Graph graph(n);
for (int i = 0; i < m; ++i) {
scanf("%d%d%d",&u,&v,&d);
graph.add_edge(u,v,d);
}
int source_node = 0;
scanf("%d",&source_node);
std::vector<int> dis = graph.get_distance(source_node);
for (int i = 1; i <= n; ++i) {
printf("%d%c",dis[i],(i == n) ? '\n' : ' ');
}
fclose(stdin);
fclose(stdout);
return 0;
}
应该不难看出这段代码的功能是拓扑排序求DAG单源最短路。
没啥。
我们直接g++ graph.cpp
可以生成一个a.out的可执行文件。
然后直接./a.out
可以运行。
运行后会生成graph.out
graph.in:
5 6
5 1 5
1 2 100
1 3 1
1 4 3
3 4 1
4 2 9
5
graph.out:
5 16 6 7 0
可以验证样例的输出结果是正确的。
写到这里,感觉博客是说vim配置还是说代码?就当时是日记好了。
那么我再记录一个,python 写的拓扑排序好了(^_^),最近也开始写python了
题目链接: 排水系统 <–
这个题,其实是2020年CSP提高组的一道题,其实就是拓扑排序+分数求和。分数的话,我们可以用Python的Fraction。
#from Queue import Queue
import threading
from queue import Queue
from queue import Empty
from fractions import Fraction
class Graph(object):
def __init__(self,cnt_node):
cnt_node = int(cnt_node)
self.cnt_node = cnt_node
self.edge = [ [] for i in range(cnt_node+1)]
self.indegree = [0 for i in range(cnt_node+1) ]
self.flow = [Fraction(0,1) for i in range(cnt_node+1)]
def add_edge(self,u,v):
self.edge[u].append(v)
self.indegree[v] += 1
def topo_sort(self):
Q = Queue()
for i in range(1,self.cnt_node+1):
if self.indegree[i] == 0:
Q.put(i)
self.flow[i] = Fraction(1,1)
while not Q.empty():
u = Q.get()
sz = len(self.edge[u])
add_flow = self.flow[u] * Fraction(1,sz) if sz != 0 else Fraction(0,1)
for v in self.edge[u]:
self.flow[v] += add_flow
self.indegree[v] -= 1
if self.indegree[v] == 0:
Q.put(v)
def main():
with open('water.in','r') as fin:
n,m = list(map(int,fin.readline().split(' ')))
graph = Graph(n)
outNode = []
for i in range(1,n+1):
arr = list(map(int,fin.readline().split(' ')))
sz = arr[0]
if sz == 0:
outNode.append(i)
for j in range(1,sz+1):
v = arr[j]
graph.add_edge(i,v)
graph.topo_sort()
with open('water.out','w') as fout:
for u in outNode:
line = str(graph.flow[u].numerator)+' '+str(graph.flow[u].denominator)
fout.write(line+"\n")
if __name__ == "__main__" :
main()
这个题,我用python的提交TLE了,只过了60%的点。
那就再上一个C++的AC代码吧
#include <queue>
#include <cstdio>
#include <vector>
#include <cassert>
#include <cmath>
using namespace std;
typedef double LL;
LL gcd(LL a, LL b) {
return fabs(b) >= 1e-6 ? gcd(b, fmod(a, b)) : a;
}
LL lcm(LL a, LL b) {
return a / gcd(a, b) * b;
}
void reduct(LL &a, LL &b) {
LL g = gcd(a, b);
a /= g;
b /= g;
}
struct Number {
LL up;
LL down;
Number() {
up = 0;
down = 1;
}
Number(LL _up, LL _down) {
up = _up;
down = _down;
}
void setNumber(int _up, int _down) {
up = _up;
down = _down;
}
friend Number operator + (const Number &opLeft, const Number &opRight) {
LL Lcm = lcm(opLeft.down, opRight.down);
LL up = opLeft.up * (Lcm / opLeft.down) + opRight.up * (Lcm / opRight.down);
reduct(Lcm, up);
return Number(up, Lcm);
}
};
int main(void) {
freopen("water.in", "r", stdin);
freopen("water.out", "w", stdout);
int n, m, d, v;;
scanf("%d%d", &n, &m);
vector<vector<int>> edge(n + 1); //邻接表
vector<int> indegree(n + 1); //记录入度
vector<int> outNode;
for (int i = 1; i <= n; ++i) {
scanf("%d", &d);
if (d == 0) {
outNode.push_back(i);
continue;
}
while (d--) {
scanf("%d", &v);
edge[i].push_back(v);
++indegree[v];
}
}
vector<Number> sum(n + 1);
queue<int> Q;
for (int i = 1; i <= n; ++i) {
if (indegree[i] == 0) {
Q.push(i);
sum[i].setNumber(1, 1);
}
}
while (!Q.empty()) {
int tp = Q.front();
Q.pop();
LL outCnt = edge[tp].size();
Number now = sum[tp];
reduct(outCnt, now.up);
now.down *= outCnt;
reduct(now.up, now.down);
for (int i = 0; i < (int)edge[tp].size(); ++i) {
int to = edge[tp][i];
sum[to] = sum[to] + now;
if (--indegree[to] == 0) {
Q.push(to);
}
}
}
for (int i = 0; i < (int)outNode.size(); ++i) {
int id = outNode[i];
printf("%.0lf %.0lf\n", sum[id].up, sum[id].down);
}
fclose(stdin);
fclose(stdout);
return 0;
}
题目不难,主要是练习一下最近学习的编码规范。
没了。bye-bye
2021.2.3 21:45