板子哲学康复练习

开学后第一次用 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]);
}
posted @ 2023-10-19 17:18  Sonnety  阅读(80)  评论(4编辑  收藏  举报