1. 程式人生 > >洛谷 P2783 有機化學之神偶爾會做作弊 解題報告

洛谷 P2783 有機化學之神偶爾會做作弊 解題報告

ext 沒有 ron push_back line str mem 成了 info

P2783 有機化學之神偶爾會做作弊

題目背景

XS中學化學競賽組教練是一個酷愛爐石的人。

有一天他一邊搓爐石一邊監考,而你作為一個信息競賽的大神也來湊熱鬧。

然而你的化競基友卻向你求助了。

“第1354題怎麽做”<--手語 他問道。

題目描述

你翻到那一題:給定一個烴,只含有單鍵(給初中生的一個理解性解釋:就是一堆碳用橫線連起來,橫線都是單條的)。

然後炎魔之王拉格納羅斯用他的火焰凈化了一切環(???)。所有的環狀碳都變成了一個碳。如圖所示。

技術分享圖片

然後指定多組碳,求出它們之間總共有多少碳。如圖所示(和上圖沒有關系)。

技術分享圖片

但是因為在考試,所以你只能把這個答案用手語告訴你的基友。你決定用二進制來表示最後的答案。如圖所示(不要在意,和題目沒有什麽沒關系)。

技術分享圖片

輸入輸出格式

輸入格式:

第一行兩個整數\(n,m\).表示有\(n\)個點,\(m\)根鍵

接下來\(m\)行每行兩個整數\(u\)\(v\)表示\(u\)號碳和\(v\)號碳有一根鍵

接下來一個整數\(tot\)表示詢問次數

接下來\(tot\)行每行兩個整數,\(a,b\)表示詢問的兩個碳的編號

輸出格式:

\(tot\)

每行一個二進制數

說明

1<n<=10000,1<m<=50000

(兩個碳不成環)


人生中第一道A掉的黑題!2018.6.9

其實這題思想上不難,簡化一下問題即是:對於一個無向圖,先把環給縮點縮掉,然後求\(LCA\)即可。

無向圖縮點
LCA


code:

#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int N=10010;
const int M=50010;
struct Edge
{
    int to,next;
}edge[M<<1],edge1[M<<1];
vector <int > g[N];
int head[N],cnt=0,n,m,head1[N],cnt1=0;
void add(int u,int v)
{
    edge[++cnt].next=head[u];edge[cnt].to=v;head[u]=cnt;
}
void add1(int u,int v)
{
    edge1[++cnt1].next=head1[u];edge1[cnt1].to=v;head1[u]=cnt1;
}
int time=0,dfn[N],low[N],used[N],ha[N],f[N],s[N],ans[N],dis[N],tot=0,n0=0;
void push(int x){s[++tot]=x;}
void pop(){tot--;}
void tarjan(int now,int fa)
{
    dfn[now]=low[now]=++time;
    push(now);
    used[now]=1;
    for(int i=head[now];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v!=fa)
        {
            if(!dfn[v])
            {
                tarjan(v,now);
                low[now]=min(low[now],low[v]);
            }
            else if(used[v])
                low[now]=min(low[now],dfn[v]);
        }
    }
    if(low[now]==dfn[now])
    {
        n0++;
        int k;
        do
        {
            k=s[tot];
            ha[k]=n0;
            used[k]=0;
            pop();
        }while(k!=now);
    }
}
int find(int x)
{
    return f[x]=f[x]==x?x:find(f[x]);
}
void merge(int x,int y)
{
    f[find(y)]=find(x);
}
void LCA(int now)//求解lca
{
    used[now]=1;
    for(int i=0;i<g[now].size();i++)
    {
        int v=g[now][i];
        if(!used[v])
        {
            LCA(v);
            merge(now,v);
        }
    }
    for(int i=head1[now];i;i=edge1[i].next)
    {
        int v=edge1[i].to;
        if(used[v])
        {
            int anc=find(v);
            ans[i+1>>1]=dis[v]+dis[now]-(dis[anc]<<1)+1;
        }
    }
}
void out(int x)
{
    int len=0,tt[20];
    while(x)
    {
        tt[++len]=x&1;
        x>>=1;
    }
    for(int i=len;i;i--)
        printf("%d",tt[i]);
    printf("\n");
}
void dfs0(int now,int dep)
{
    used[now]=1;
    dis[now]=dep;
    for(int i=0;i<g[now].size();i++)
    {
        int v=g[now][i];
        if(!used[v]) dfs0(v,dep+1);
    }
}
void init()
{
    for(int i=1;i<=n0;i++) f[i]=i;
    for(int i=1;i<=n0;i++)
        if(!used[i])
            dfs0(i,1);
}
int main()
{
    scanf("%d%d",&n,&m);
    int u,v,q;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            tarjan(i,0);
    for(int i=1;i<=n;i++)
        for(int j=head[i];j;j=edge[j].next)
        {
            int v=edge[j].to;
            if(ha[v]!=ha[i])
                g[ha[i]].push_back(ha[v]);
        }
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d",&u,&v);
        add1(ha[u],ha[v]);
        add1(ha[v],ha[u]);
    }
    init();
    memset(used,0,sizeof(used));
    for(int i=1;i<=n0;i++)
        if(!used[i])
            LCA(i);
    for(int i=1;i<=q;i++)
        out(ans[i]);
    return 0;
}

2018.6.9

洛谷 P2783 有機化學之神偶爾會做作弊 解題報告