板子哲学康复练习
开学后第一次用 Windows 打代码,有种唐氏儿的美。
Tarjan
tarjan 求强连通
不知道有没有过编,但大概没错。
Miku's Code
#include<bits;/stdc++.h>
#define rg register int
#define il inline
il int Min(int x,int y){ return x<y?x:y; }
il int Max(int x,int y){ return x<y?y:x; }
il int Abs(int x,int y){ return x<0?-x:x; }
il int read(){
char c=getchar();int f=1,x=0;
while(c<48){ if(c=='-')f=-1;c=getchar(); }
while(c>47){ x=(x<<3)+(x<<1)+(c^48);c=getchar(); }
return x*f;
}
int n,m,a[maxn];
int dfn[maxn],
int head[maxn<<1],t;
struct Edge{ int v,w;int next; };Edge e[maxn<<1];
il void add_edge(int u,int v,int w){ e[++t].v=v;e[t].w=w;e[t].next=head[u];head[u]=t; }
void tarjan(int now){
dfn[now]=low[now]=++cnt;
for(rg i=head[now];i;i=e[i].next){
int to=e[i].v;
if(!dfn[to]){
tarjan(to);
low[now]=Min(low[now],low[to]);
}
else if(vis[to]) low[now]=Min(low[now],dfn[to]);
}
if(dfn[now]==low[now]){
int cur;++id;
do{
cur=stk[top--];vis[cur]=false;
scc[cur]=id;++siz[id];
}while(cur!=now);
}
}
il void input(){
n=read(),m=read();int u,v,w;
for(rg i=1;i<=n;++i) a[i]=read();
for(rg i=1;i<=m;++i) u=read(),v=read(),w=read(),add_edge(u,v,w);
}
int main(){
input();
for(rg i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
return 0;
}
tarjan 求环
写了一个最小环版本的,过了。
恼了,有强联通分量好像 tarjan 没法求环,那打好像没啥意义啊。
Miku's Code
#include<bits/stdc++.h>
#define rg register int
#define il inline
#define cerr std::cerr
#define endl '\n'
il int Max(int x,int y){ return x<y?y:x; }
il int Min(int x,int y){ return x<y?x:y; }
il int Abs(int x){ return x<0?-x:x; }
il int read(){
char c=getchar();int x=0,f=1;
while(c<48){ if(c=='-')f=-1;c=getchar(); }
while(c>47){ x=(x<<3)+(x<<1)+(c^48);c=getchar(); }
return x*f;
}const int maxn=2e5+5,inf=0x3f3f3f3f;
int n,m,minn,id,a[maxn],dfn[maxn],low[maxn],tot,stk[maxn],top;
bool invis[maxn];
int head[maxn<<1],t;
struct Edge{ int v;int next; };Edge e[maxn<<1];
il void add_edge(int u,int v){ e[++t].v=v;e[t].next=head[u];head[u]=t; }
void tarjan(int now){
dfn[now]=low[now]=++tot;
stk[++top]=now;invis[now]=true;
for(rg i=head[now];i;i=e[i].next){
int to=e[i].v;
if(!dfn[to]){
tarjan(to);
low[now]=Min(low[now],low[to]);
}
else if(invis[to]) low[now]=Min(low[now],dfn[to]);
}
if(dfn[now]==low[now]){
int cur=stk[top],count_=0;
while(cur!=now){
++count_;invis[cur]=false;
--top;cur=stk[top];
}
++count_;
invis[cur]=false;--top;
if(count_>1) minn=Min(minn,count_);
}
}
il void input(){
n=read();int v;
for(rg i=1;i<=n;++i) v=read(),add_edge(i,v);
}
int main(){
// freopen("tarjan.in","r",stdin);
input();minn=inf;
for(rg i=1;i<=n;++i) if(!dfn[i]) tarjan(i);
printf("%d\n",minn);
return 0;
}
tarjan 求点双
我去我不会啊,抄了一遍板子。
Miku's Code
// 点双联通:删掉一个点后子图仍为强联通分量
#include<bits/stdc++.h>
#define il inline
#define rg register int
#define cerr std::cerr
#define endl '\n'
il int Min(int x,int y){ return x<y?x:y; }
il int Max(int x,int y){ return x<y?y:x; }
il int Abs(int x){ return x<0?-x:x; }
il int read(){
char c=getchar();int x=0,f=1;
while(c<48){ if(c=='-')f=-1;c=getchar(); }
while(c>47){ x=(x<<3)+(x<<1)+(c^48);c=getchar(); }
return x*f;
}const int maxn=1e5+5,maxm=3e5+5;
int n,m,dfn[maxn],low[maxn],tot,stk[maxn],top,rt,cut[maxn],id[maxn],num;
bool invis[maxn];
int head[maxm<<1],t;
struct Edge{ int u,v;int next; };Edge e[maxm];
il void add_edge(int u,int v){ e[++t].v=v;e[t].next=head[u];head[u]=t; }
std::vector<int> g[maxn];
std::vector<int> dcc[maxn];int rc;
void tarjan(int now){
dfn[now]=low[now]=++tot;
stk[++top]=now;invis[now]=true;
if(now==rt && !head[now]) return dcc[++rc].push_back(now),void();
int child=0;
for(rg i=head[now];i;i=e[i].next){
int to=e[i].v;
if(!dfn[to]){
tarjan(to);
low[now]=Min(low[now],low[to]);
if(low[now]>=dfn[now]){
++child;
if(now!=rt || child>1) cut[now]=true;
++rc;
printf("vDCC:");
int cur=stk[top];
while(cur!=to){
dcc[rc].push_back(cur);printf("%d ",cur);
--top;cur=stk[top];
}
dcc[rc].push_back(cur);printf("%d ",cur);
--top;
dcc[rc].push_back(now),printf("%d",now);
}
}
else if(invis[to]) low[now]=Min(low[now],dfn[to]);
}
}
int main(){
input();
for(rt=1;rt<=n;++rt) if(!dfn[rt]) tarjan(rt);
for(rg i=1;i<=n;++i) if(cut[i]) id[i]=++num;
memset(head,0,sizeof(head));t=0;
for(rg i=1;i<=rc;++i){
for(rg j=0;j<dcc[i].size();++j){
int x=dcc[i][j];
if(cut[x]) g[i].push_back(id[x]),g[id[x]].push_back(i);
}
}
return 0;
}
tarjan 求边双
本来想写一个还需要多少边可连边双,但是懒得写了。
抄了遍板子,恼了,为啥我啥也不会。
Miku's Code
#include<bits/stdc++.h>
const int maxn=5e3+5,maxm=3e5+5;
int n,m,rt,dfn[maxn],low[maxn],tot,dcc[maxn],cnt;
bool cut[maxn],invis[maxn];
int stk[maxn],top;
int head[maxm],t;
struct Edge{ int v;int next; };Edge e[maxm];
il void add_edge(int u,int v){ e[++t].v=v;e[t].next=head[u];head[u]=t; }
void tarjan(int now,int fa){
dfn[now]=low[now]=++tot;
stk[++top]=now;invis[now]=true;
for(rg i=head[now];i;i=e[i].next){
int to=e[i].v;
if(to==fa) continue;
if(!dfn[to]){
tarjan(to,now);
low[now]=Min(low[now],low[to]);
}
else if(vis[to]) low[now]=Min(low[now],low[to]);
}
if(dfn[now]==low[now]){
++cnt;int cur=stk[top];
while(cur!=now){
dcc[cur]=cnt;
--top;cur=stk[top];invis[cur]=false;
}
invis[cur]=false;dcc[cur]=cnt;--top;
}
}
int main(){
tarjan(1,0);
}
ST 表
应该没错,好像如果要检查的话还要🐎倍增,但是懒。
Miku's Code
#include<bits/stdc++.h>
#define il inline
#define rg register int
#define cerr std::cerr
#define endl '\n'
il int Max(int x,int y){ return x<y?y:x; }
il int Min(int x,int y){ return x<y?x:y; }
il int Abs(int x){ return x<0?-x:x; }
il int read(){
char c=getchar();int x=0,f=1;
while(c<48){ if(c=='-')f=-1;c=getchar(); }
while(c>47){ x=(x<<3)+(x<<1)+(c^48);c=getchar(); }
return x*f;
}const int maxn=5e5+5;
int n,q,max[maxn][20],min[maxn][20];
int query_max(int l,int r){
int k=log2(r-l+1);
return Max(max[l][k],max[r-(1<<k)+1][k]);
}
int query_min(int l,int r){
int k=log2(r-l+1);
return Min(min[l][k],min[r-(1<<k)+1][k]);
}
il void input(){
n=read(),q=read();
for(rg i=1;i<=n;++i) max[i][0]=min[i][0]=read();
for(rg j=1;j<19;++j)
for(rg i=1;i+(1<<j)-1<=n;++i){
max[i][j]=Max(max[i][j-1],max[i+(1<<(j-1))][j-1]);
min[i][j]=Min(min[i][j-1],min[i+(1<<(j-1))][j-1]);
}
}
int main(){
input();
return 0;
}
最短路&最小生成树
Floyed
呃呃,复习一个 Floyed 求最小环吧,过了。
Miku's Code
#include<bits/stdc++.h>
#define il inline
#define rg register int
#define cerr std::cerr
#define endl '\n'
#define int long long
il int Max(int x,int y){ return x<y?y:x; }
il int Min(int x,int y){ return x<y?x:y; }
il int Abs(int x){ return x<0?-x:x; }
il int read(){
char c=getchar();int x=0,f=1;
while(c<48){ if(c=='-')f=-1;c=getchar(); }
while(c>47){ x=(x<<3)+(x<<1)+(c^48);c=getchar(); }
return x*f;
}const int maxn=105,maxm=5e3+5,inf=0x3f3f3f3f3f3f;
int n,m;
int dis[maxn][maxn],dist[maxn][maxn],ans;
struct Edge{ int v,w; };Edge e[maxm];
il void floyed(){
ans=inf;
for(rg k=1;k<=n;++k){
for(rg i=1;i<k;++i)
for(rg j=i+1;j<k;++j) ans=Min(ans,dist[i][j]+dis[i][k]+dis[k][j]);
for(rg i=1;i<=n;++i)
for(rg j=1;j<=n;++j) dist[i][j]=dist[j][i]=Min(dist[i][j],dist[i][k]+dist[k][j]);
}
}
il void input(){
n=read(),m=read();int u,v,w;
for(rg i=1;i<=n;++i) for(rg j=1;j<i;++j) dis[i][j]=dis[j][i]=dist[i][j]=dist[j][i]=inf;
for(rg i=1;i<=m;++i) u=read(),v=read(),w=read(),dist[u][v]=dist[v][u]=dis[u][v]=dis[v][u]=Min(dis[u][v],w);
}
signed main(){
input();
floyed();
(ans==inf)?puts("No solution."):printf("%d\n",ans);
return 0;
}
堆优化 dijkstra
哈哈,这个要是错了真是贻笑大方了。
Miku's Code
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define rg register int
typedef std::pair<int,int> PII;
il int Max(int x,int y){ return x<y?y:x; }
il int Min(int x,int y){ return x<y?x:y; }
il int Abs(int x){ return x<0?-x:x; }
il int read(){
char c=getchar();int x=0,f=1;
if(c<48){ if(c=='-')f=-1;c=getchar(); }
if(c>47){ x=(x<<3)+(x<<1)+(c^48);c=getchar(); }
return x*f;
}const int maxn=5e5+5,inf=0x3f3f3f3f;
int n,m,dis[maxn],ans;
这里是链式前向星
bool vis[maxn];
il void clear(){ for(rg i=0;i<=n;++i) dis[i]=inf,vis[i]=false; }
void dijkstra(int now){
clear();
dis[now]=0;
std::priority_queue<PII,vector<PII>,greater<PII>> heap;
while(!heap.empty()) heap.pop();
heap.push(make_pair(0,now));
while(!heap.empty()){
PII t=heap.top();heap.pop();
int temp=t.second,distance=t.first;
if(vis[temp]==true) continue;
vis[temp]=true;
for(rg i=head[temp];i;i=e[i].next){
int j=e[i].v;
if(distance+e[i].w<dis[j]) dis[j]=distance+e[i].w,heap.push(make_pair(dis[j],j));
}
}
}
int main(){
return 0;
}
kruskal 最小生成树
跟板子对过了,应该没错。
Miku's Code
#include<bits/stdc++.h>
#define il inline
#define rg register int
il int Max(int x,int y){ return x<y?y:x; }
il int Min(int x,int y){ return x<y?x:y; }
il int Abs(int x){ return x<0?-x:x; }
il int read(){
char c=getchar();int x=0,f=1;
while(c<48){ if(c=='-')f=-1;c=getchar(); }
while(c>47){ x=(x<<3)+(x<<1)+(c^48);c=getchar(); }
return x*f;
}const int maxn=1e5+5,maxm=3e5+5;
int n,m,fa[maxn];
int getfa(int x){ return fa[x]==x?x:fa[x]=getfa(fa[x]); }
int head[maxn<<1],t;
struct Edge{
int u,v,w;int next;
Edge()=default;
Edge(int uu,int vv,int ww):u(uu),v(vv),w(ww) {}
bool operator<(const Edge &e){ return w<e.w; }
};Edge g[maxm],e[maxn<<1];
il void add_edge(int u,int v,int w){ e[++t].v=v;e[t].next=head[u];head[u]=t; }
il void kruskal(){
std::sort(g+1,g+1+m);
for(rg i=1;i<=m;++i){
if(getfa(g[i].u)!=getfa(g[i].v)){
add_edge(g[i].u,g[i].v,g[i].w);add_edge(g[i].v,g[i].u,g[i].w);
fa[g[i].u]=getfa(e[i].v);
}
}
}
il void input(){
n=read(),m=read();
for(rg i=1;i<=n;++i) fa[i]=i;
for(rg i=1;i<=m;++i) g[i]=Edge(read(),read(),read());
}
int main(){
input();
kruskal();
return 0;
}
Borůvka (Sollin)
时间复杂度 \(O(mlogn)\)。
Miku's Code
#include<bits/stdc++.h>
#define il inline
#define rg register int
il int Max(int x,int y){ return x<y?y:x; }
il int Min(int x,int y){ return x<y?x:y; }
il int Abs(int x){ return x<0?-x:x; }
il int read(){
char c=getchar();int x=0,f=1;
while(c<48){ if(c=='-')f=-1;c=getchar(); }
while(c>47){ x=(x<<3)+(x<<1)+(c^48);c=getchar(); }
return x*f;
}const int maxn=5e3+5,maxm=2e5+5,inf=0x3f3f3f3f;
int n,m,fa[maxn],ans,res;
int getfa(int x){ return x==fa[x]?x:fa[x]=getfa(fa[x]); }
struct Edge{
int u,v,w,id;
Edge()=default;
Edge(int uu,int vv,int ww,int temp):u(uu),v(vv),w(ww),id(temp) {}
};Edge e[maxm];
int minn[maxm],eid[maxm];
bool vis[maxm];
il void Boruvka(){
for(rg i=1;i<=n;++i) fa[i]=i;
while(1){
int cnt=0;
for(rg i=1;i<=n;++i) minn[i]=inf;
for(rg i=1;i<=m;++i){
int fx=getfa(e[i].u),fy=getfa(e[i].v),w=e[i].w;
if(fx==fy) continue;
++cnt;
if(w<minn[fx] || (w==minn[fx] && e[i].id<eid[fx])) minn[fx]=w,eid[fx]=e[i].id;
if(w<minn[fy] || (w==minn[fy] && e[i].id<eid[fy])) minn[fy]=w,eid[fy]=e[i].id;
}
if(cnt==0) break;
for(rg i=1;i<=n;++i){
if(minn[i]!=inf && !vis[eid[i]]){
fa[getfa(e[eid[i]].u)]=getfa(e[eid[i]].v);
ans+=e[eid[i]].w;++res;
vis[eid[i]]=true;
}
}
}
}
il void input(){
n=read(),m=read();
for(rg i=1;i<=m;++i) e[i]=Edge(read(),read(),read(),i);
}
int main(){
input();
Boruvka();
return 0;
}
KMP
如果要考字符串的话,感觉大概率考 KMP 了啊。
Miku's Code
#include<bits/stdc++.h>
#define il inline
#define rg register
const int maxn=1e5+5;
char s[maxn],p[maxn];
int slen,plen,next[maxn];
il void Next(){
next[1]=0;
for(rg i=2,j=0;i<=plen;++i){
while(j && p[i]!=p[j+1]) j=next[j];
if(p[i]==p[j+1]) ++j;
next[i]=j;
}
}
void KMP(){
int i=1,j=0,ans=0;
for(rg i=1;i<=slen;++i){
while(j && s[i]!=p[j+1]) j=next[j];
if(s[i]==p[j+1]) ++j;
if(j==plen){ printf("%d\n",i-j+1);j=next[j]; }
}
}
int main(){
scanf("%s %s",s+1,p+1);slen=strlen(s+1),plen=strlen(p+1);
Next();
KMP();
return 0;
}
高斯消元
Miku's Code
#include<bits/stdc++.h>
#define il inline
#define rg register int
il int read(){
char c=getchar();int x=0,f=1;
while(c<48){ if(c=='-')f=-1;c=getchar(); }
while(c>47){ x=(x<<3)+(x<<1)+(c^48);c=getchar(); }
return x*f;
}
int n,y;
double a[114][514];
void Guass(){
for(rg i=1;i<=n;++i){
y=i;
while(a[y][i]==0 && y<=n) ++y;
if(y==n+1) return printf("No Solution"),void();
for(rg j=1;j<=n+1;++j) std::swap(a[i][j],a[y][j]);
double k=a[i][i];
for(rg j=1;j<=n+1;++j) a[i][j]/=k;
for(rg j=1;j<=n;++j)
if(i!=j){
double ji=a[j][i];
for(rg q=1;q<=n+1;++q) a[j][q]-=ki*a[i][q];
}
}
}
int main(){
n=read();
for(rg i=1;i<=n;++i) for(rg j=1;j<=n+1;++j) scanf("%lf",&a[i][j]);
Guass();
for(rg i=1;i<=n;++i) printf("%.2f\n",a[i][n+1]);
}