几道图论题的一句话题解

CF118E Bertown roads

Codeforces 118E Bertown roads

题意:无向连通图,给边定向,使其强连通。

题解:DFS,树边向下连,返祖边向上连,注意判断无解。

#include<bits/stdc++.h>
using namespace std;
int getint(){ int x;scanf("%d",&x);return x; }
const int N=1e5+10,M=6e5+10;
struct bian{
    int l,e,n;
};
bian b[M];
int s[N],tot=1;
void add(int x,int y){
    tot++;
    b[tot].e=y;
    b[tot].n=s[x];
    s[x]=tot;
}

bool vis[N];
int nfd[N],dfnn=0;
void ss0(int x){
    vis[x]=1;
    for(int i=s[x];i;i=b[i].n){
        if(vis[b[i].e]){ if(!b[i^1].l) b[i].l=1; continue; }
        b[i].l=1;
        ss0(b[i].e);
    }
}
void ss1(int x){
    vis[x]=1;
    for(int i=s[x];i;i=b[i].n){
        if(b[i].l)continue;
        if(vis[b[i].e])continue;
        ss1(b[i].e);
    }
}

int main(){
    int n=getint(),m=getint();
    for(int i=0;i<m;i++){
        int x=getint(),y=getint();
        add(x,y);
        add(y,x);
    }
    ss0(1);
    memset(vis,0,sizeof(bool)*(n+2));
    ss1(1);
    bool ok=1;
    for(int i=1;i<=n;i++)if(!vis[i])ok=0;
    if(!ok)puts("0");
    else for(int i=1;i<=n;i++)for(int j=s[i];j;j=b[j].n)if(b[j].l)printf("%d %d\n",i,b[j].e);
}

CF231E Cactus

Codeforces 231E Cactus

题意:给定一点仙人掌,多次询问 \(u\)\(v\) 的简单路径数量。

题解:每个环会让答案 \(\times 2\);于是把环缩成点,询问即在树上统计链上有多少环缩成的点。

#include<bits/stdc++.h>
using namespace std;
int getint(){ int x;scanf("%d",&x);return x; }
const int N=2e5+10,M=4e5+10;
struct bian{
    int l,e,n;
};
bian b[M];
int s[N],tot=1;
void add(int x,int y){
    tot++;
    b[tot].e=y;
    b[tot].n=s[x];
    s[x]=tot;
}
int v[N];
int col[N];

namespace Graph{

bian b[M];
int s[N],tot=1;
void add(int x,int y){
    tot++;
    b[tot].e=y;
    b[tot].n=s[x];
    s[x]=tot;
}
int stk[N],top;
bool vis[N];
bool instk[N];
int cnt;
void ss(int x,int fa){
    stk[top++]=x;
    instk[x]=1;
    vis[x]=1;
    for(int i=s[x];i;i=b[i].n){
        int v=b[i].e;
        if(i==(fa^1))continue;
        if(!vis[v])ss(v,i);
        if(instk[v]){
            ++cnt;
            while(stk[top]!=v){
                --top;
                col[stk[top]]=cnt;
            }
            ::v[cnt]++;
        }
    }
    instk[x]=0;
    if(!col[x])col[x]=++cnt,--top;
//    cerr<<x<<"! ";for(int i=0;i<top;i++)cerr<<" "<<stk[i];cerr<<endl;
}

} // namespace Graph

const int L=18;
int f[L][N],dep[N];
bool vis[N];
void ss(int x,int fa){
    vis[x]=1;
    for(int i=s[x];i;i=b[i].n){
    	int v=b[i].e;
        if(vis[v])continue;
        ::v[v]+=::v[x];
        dep[v]=dep[x]+1;
        f[0][v]=x;
        ss(b[i].e,x);
    }
}
void init_lca(int n){
    for(int i=1;i<L;i++)
        for(int j=1;j<=n;j++)f[i][j]=f[i-1][f[i-1][j]];
}
int lca(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    for(int i=L-1;i>=0;i--)if(dep[f[i][x]]>=dep[y])x=f[i][x];
    if(x==y)return x;
    for(int i=L-1;i>=0;i--)if(f[i][x]!=f[i][y])x=f[i][x],y=f[i][y];
    return f[0][x];
}
int query(int x,int y){
    int l=lca(x,y);
    return v[x]+v[y]-v[l]-v[f[0][l]];
}
int p2[N];

int main(){
    int n=getint(),m=getint();
    for(int i=0;i<m;i++){
        int x=getint(),y=getint();
        Graph::add(x,y);
        Graph::add(y,x);
    }
    Graph::ss(1,0);
    for(int i=1;i<=n;i++)for(int j=Graph::s[i];j;j=Graph::b[j].n)
        add(col[i],col[Graph::b[j].e]),
        add(col[Graph::b[j].e],col[i]);
    dep[1]=1;
    ss(1,0);
    p2[0]=1;
    for(int i=1;i<=n;i++)p2[i]=p2[i-1]*2ll%1000000007;
    n=Graph::cnt;
    init_lca(n);
    int q=getint();
    while(q--){
        int x=getint(),y=getint();
        printf("%d\n",p2[query(col[x],col[y])]);
    }
}

CF412D Giving Awards

Codeforces 412D Giving Awards

题意:给定一有向图,保证没有反向平行边,求其补图的哈密顿回路。

题解:DFS 树上的后序遍历。

#include<bits/stdc++.h>
using namespace std;
int getint(){ int x;scanf("%d",&x);return x; }
const int N=1e5+10,M=6e5+10;
struct bian{
    int l,e,n;
};
bian b[M];
int s[N],tot=0;
void add(int x,int y){
    tot++;
    b[tot].e=y;
    b[tot].n=s[x];
    s[x]=tot;
}

bool vis[N];
void ss(int x){
    vis[x]=1;
    for(int i=s[x];i;i=b[i].n){
        if(vis[b[i].e])continue;
        ss(b[i].e);
    }
    printf("%d ",x);
}

int main(){
    int n=getint(),m=getint();
    for(int i=0;i<m;i++){
        int x=getint(),y=getint();
        add(x,y);
    }
    for(int i=1;i<=n;i++)if(!vis[i])ss(i);
}

CF858F Wizard's Tour

codeforces 858F Wizard's Tour

题意:将无向图的编辑化为多个 \((u,v),(v,w)\)

题解:DFS,贪心,可能多余出来的一条边留给父亲。

#include<bits/stdc++.h>
using namespace std;
int getint(){ int x;scanf("%d",&x);return x; }
const int N=2e5+10,M=4e5+10;
struct bian{
    int l,e,n;
};
bian b[M];
int s[N],tot=1;
void add(int x,int y){
    tot++;
    b[tot].e=y;
    b[tot].n=s[x];
    s[x]=tot;
}

vector<tuple<int,int,int> >v;
bool vis[N];
void ss(int x,int fa){
    vis[x]=1;
    int lst=0;
    for(int i=s[x];i;i=b[i].n){
        if(i==(fa^1))continue;
        if(!vis[b[i].e])ss(b[i].e,i);
        if(!b[i].l){
            if(lst){
                b[i].l=1; b[i^1].l=1;
                b[lst].l=1; b[lst^1].l=1;
                v.emplace_back(b[lst].e,x,b[i].e);
                lst=0;
            }else lst=i;
        }
    }
    if(lst&&fa){
        b[fa].l=1; b[fa^1].l=1;
        b[lst].l=1; b[lst^1].l=1;
        v.emplace_back(b[lst].e,x,b[fa^1].e),lst=0;
    }
}

int main(){
    int n=getint(),m=getint();
    for(int i=0;i<m;i++){
        int x=getint(),y=getint();
        add(x,y);
        add(y,x);
    }
    for(int i=1;i<=n;i++)if(!vis[i])ss(i,0);
    printf("%d\n",v.size());
    for(auto i:v)printf("%d %d %d\n",get<0>(i),get<1>(i),get<2>(i));
}

洛谷 P5540 [BalkanOI2011] timeismoney | 最小乘积生成树

P5540 [BalkanOI2011] timeismoney | 最小乘积生成树

题意:无向图,每条边有权值 \(a_i,b_i\),求生成树,最小化 \((\sum_i a_i)\times (\sum_i b_i)\)

题解:最优解一定在下凸包上,于是我们凸包上二分。具体地,我们令斜率为 \(k\),则令边权为 \(ka+b\) 并求 MST。

#include<bits/stdc++.h>
using namespace std;
inline int getint(){
    int ans=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        ans=ans*10+c-'0';
        c=getchar();
    }
    return ans*f;
}
#define ll long long
#define pii pair<int,int>
#define fi first
#define se second
const int N=200,M=10010;
struct bian{
    int s,t,x,y;
};
bian b[M];
int n,m;
double k1,k2;
inline bool operator<(bian a,bian b){
    return a.x*k1+a.y*k2<b.x*k1+b.y*k2;
}
int f[N];inline int _(int x){ return x==f[x]?x:f[x]=_(f[x]); }
inline ll abs(pii p){
    return p.fi*1ll*p.se;
}
inline pii mst(double k1,double k2){
    ::k1=k1;::k2=k2;
    sort(b,b+m);
    for(int i=0;i<=n;i++)f[i]=i;
    pii ans;
    int cnt=0;
    for(int i=0;i<m;i++){
        int x=_(b[i].s),y=_(b[i].t);
        if(x==y)continue;
        ans.fi+=b[i].x;
        ans.se+=b[i].y;
        f[x]=y;
        ++cnt;
        if(cnt==n-1)break;
    }
    return ans;
}
inline pii solve(pii p,pii q,int dep=0){
    pii ans=abs(p)<abs(q)?p:q;
    if(p.fi==q.fi||p.se==q.se)return ans;
    double k=(q.se-p.se*1.0)/(p.fi-q.fi);
    pii r=mst(k,1);
    //cerr<<string(dep,' ')<<"solve "<<p.fi<<" "<<p.se<<" "<<q.fi<<" "<<q.se<<"  "<<r.fi<<" "<<r.se<<"  "<<ans<<endl;
    if(r.fi*k+r.se-
       q.fi*k-q.se>-1e-8)return ans;
    pii t=solve(r,p,dep+1);
    ans=abs(ans)<abs(t)?ans:t;
    t=solve(q,r,dep+1);
    ans=abs(ans)<abs(t)?ans:t;
    return ans;
}
inline pii solve(){
    pii p1,p2;
    p1=mst(1,0);
    p2=mst(0,1);
    if(p1.fi<0||p2.se<0)return pii(0,0);
    return solve(p1,p2);
}
int main(){
    n=getint(),m=getint();
    for(int i=0;i<m;i++)b[i].s=getint(),b[i].t=getint(),b[i].x=getint(),b[i].y=getint();
    pii ans=solve();

    cout<<ans.first<<" "<<ans.second<<endl;
}

posted @ 2021-04-06 19:26  破壁人五号  阅读(124)  评论(0编辑  收藏  举报