2015-2016 下半学期 第十周 训练

来源:互联网 发布:sql with树形 编辑:程序博客网 时间:2024/05/18 01:46

1、hdu4612

题意:

无向图连一条边后桥边数量最少是多少。

思路:

先将无向图缩点形成一棵树,再两次dfs取直径,在直径端点连边,这样可以使桥边减少的最多。

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <stack>#include <queue>using namespace std;const int maxn=200000+100;struct Edge{    int v, nxt;} edge[3000010];int n, m;int pre[maxn], low[maxn], dfn, head[maxn], tot;int belong[maxn], block, bridge;stack<int> S;bool ins[maxn];void init(){    memset(head, -1, sizeof head);    memset(pre, 0, sizeof pre);    memset(low, 0, sizeof low);    memset(ins, 0, sizeof ins);    memset(belong, 0, sizeof belong);    dfn=tot=block=bridge=0;}void AddEdge(int u, int v){    edge[tot].v=v;    edge[tot].nxt=head[u];    head[u]=tot++;}void Tarjan(int u, int fa){    pre[u]=low[u]=++dfn;    S.push(u);    ins[u]=true;    for(int i=head[u]; ~i; i=edge[i].nxt)    {        if(i==(fa^1))continue ;        int v=edge[i].v;        if(!ins[v])        {            Tarjan(v, i);            low[u]=min(low[u], low[v]);            if(low[v]>pre[u])                bridge++;        }        else low[u]=min(low[u], pre[v]);    }    if(low[u]==pre[u])    {        block++;        while(true)        {            int x=S.top();            S.pop();            ins[x]=false;            belong[x]=block;            if(x==u)break;        }    }}vector<int> G[maxn];int d[maxn];bool vis[maxn];queue<int> q;int bfs(int s, int& ans){    memset(d, 0, sizeof d);    memset(vis, 0, sizeof vis);    int t=s, head=0, tail=0;    q.push(s);    vis[s]=true;    while(!q.empty())    {        int u=q.front();        q.pop();        for(int i=0; i<G[u].size(); i++)        {            int v=G[u][i];            if(!vis[v])            {                vis[v]=true;                d[v]=d[u]+1;                if(d[v]>ans)                    ans=d[t=v];                q.push(v);            }        }    }    return t;}int main(){    while(~scanf("%d%d", &n, &m) && n+m)    {        init();        while(m--)        {            int u, v;            scanf("%d%d", &u, &v);            AddEdge(u, v);            AddEdge(v, u);        }        for(int i=1; i<=n; i++)            if(!pre[i])                Tarjan(i, -1);        for(int i=0; i<=n; i++)            G[i].clear();        for(int u=1; u<=n; u++)            for(int i=head[u]; ~i; i=edge[i].nxt)            {                int v=edge[i].v;                if(belong[u]!=belong[v])                    G[belong[u]].push_back(belong[v]);            }        int ans=0;        int key=bfs(1, ans);        bfs(key, ans);        printf("%d\n", bridge-ans);    }    return 0;}

2、去掉两个点,问可以最多留下多少个连通分支。

思路:n^2枚举

代码:

#include<cstdio>#include<iostream>#include<vector>#include<cstring>#include<algorithm>#define MAX_N 5555using namespace std;vector<int> G[MAX_N];bool vis[MAX_N];int dfn[MAX_N],low[MAX_N],ind=0;int cut[MAX_N];int node;void Tarjan(int u,int p){    int child=0;    dfn[u]=low[u]=++ind;    vis[u]=1;    for(int i=0;i<G[u].size();i++){        int v=G[u][i];        if(v==p||v==node)continue;        if(!vis[v]){            Tarjan(v,u);            low[u]=min(low[v],low[u]);            child++;            if((p==-1&&child>1)||(p!=-1&&low[v]>=dfn[u]))                cut[u]++;        }        else            low[u]=min(dfn[v],low[u]);    }}int n,m;void init(){    for(int i=0;i<=n;i++)G[i].clear();    ind=0;    memset(vis,0,sizeof(vis));    memset(cut,0,sizeof(cut));}bool used[MAX_N];int cu;void dfs(int u,int p){    if(u==p||used[u]||u==node||u==cu)return;    used[u]=1;    for(int i=0;i<G[u].size();i++)dfs(G[u][i],u);}int main(){    while(scanf("%d%d",&n,&m)==2){        int stab=1;        init();        int u,v;        for(int i=0;i<m;i++) {            scanf("%d%d", &u, &v);            G[u].push_back(v);            G[v].push_back(u);        }        for(int i=0;i<n;i++){            node=i;            memset(vis,0,sizeof(vis));            ind=0;            memset(cut,0,sizeof(cut));            for(int j=0;j<n;j++)                if((!vis[j])&&j!=node)                    Tarjan(j,-1);            int maxC=0;            for(int j=0;j<n;j++)                if(j!=node&&cut[j]>=maxC){                    cu=j;                    maxC=cut[j];                }            int ans=0;            memset(used,0,sizeof(used));            for(int j=0;j<n;j++)                if((!used[j])&&j!=node&&j!=cu){                    dfs(j,-1);                    ans++;                }            stab=max(stab,ans);        }        printf("%d\n",stab);    }    return 0;}

3、poj3694

题意:

思路:缩点后形成一棵树,加边后成环,环内所有的边都会变成非桥边 标记去重 减去即可。

代码:

<span style="font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;">#include<iostream>#include<algorithm>#include<cstring>#include<cstdio>using namespace std;const int M=100005;struct Eage                ///邻接表建图{    int v;    int next;    int vs;};Eage eage[M*4];int low[M],dfn[M],father[M];  ///father[i]为i的父亲节点int flag[M],vs[M],head[M];    ///falg[i]为i和i的父亲节点的边int dfs_cut,ans,k;void Init(){    memset(dfn,0,sizeof(dfn));    memset(low,0,sizeof(low));    memset(flag,0,sizeof(flag));    memset(vs,0,sizeof(vs));    memset(head,-1,sizeof(head));    dfs_cut=ans=k=0;}void add(int u,int v){    eage[k].v=v;    eage[k].vs=0;    eage[k].next=head[u];    head[u]=k++;}void dfs(int u)                     ///求桥{    vs[u]=1;    dfn[u]=low[u]=++dfs_cut;    for (int i=head[u];i!=-1;i=eage[i].next)    {        if (!eage[i].vs)        {            eage[i].vs=eage[i^1].vs=1;            int v=eage[i].v;            if (!vs[v])            {                father[v]=u;                dfs(v);                low[u]=min(low[u],low[v]);                if (dfn[u]<low[v])                {                    ans++;                    flag[v]=1;                }            }            else low[u]=min(low[u],dfn[v]);        }    }}void Lca(int u,int v){    if (dfn[u]<dfn[v])    {        u^=v;        v^=u;        u^=v;    }    while (dfn[u]>dfn[v])    {        if (flag[u]) ans--;        flag[u]=0;        u=father[u];    }    while (u!=v)    {        if (flag[v]) ans--;        if (flag[u]) ans--;        flag[u]=0;        flag[v]=0;        v=father[v];        u=father[u];    }}int main(){  int n,m,cut=0;    while (cin>>n>>m)    {        if (!n&&!m) return 0;        Init();        for (int i=1;i<=n;i++) father[i]=i;        int u,v;        while (m--)        {            cin>>u>>v;            add(u,v);            add(v,u);        }        dfs(1);        cout<<"Case "<<++cut<<":"<<endl;        int q;        cin>>q;        while (q--)        {            cin>>u>>v;            Lca(u,v);            cout<<ans<<endl;        }        cout<<endl;    }    return 0;}</span>

4、poj1904

题意:

思路:奇怪的二分图+强连通分量 不会。

代码:

<span style="font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;">#include<cstdio>#include<cstring>#include<climits>#include<iostream>#include<algorithm> #define N 2010 namespace Fio{    inline int getc(){#ifdef ONLINE_JUDGE        static const int L=1<<15;#else        static const int L=1<<1;#endif        static char buf[L],*S=buf,*T=buf;        if(S==T){T=(S=buf)+fread(buf,1,L,stdin);if(S==T)return EOF;}        return*S++;    }    inline bool digit(int c){return c>='0'&&c<='9';}    template<typename T>inline void Get(T&x){        int c;while(!digit(c=getc()));x=c-'0';while(digit(c=getc()))x=(x<<1)+(x<<3)+c-'0';    }    char buf[5000000],*o=buf;    inline void putc(char c){*o++=c;}    template<typename T>inline void print(T x){        static int stk[100];int top=0;        for(;x;x/=10)stk[++top]=x%10;for(int i=top;i>=1;--i)*o++='0'+stk[i];    }    inline void Final(){fwrite(buf,1,o-buf,stdout);}} int head[4010],next[2010*2010],end[2010*2010];inline void addedge(int a,int b){static int q=1;end[q]=b,next[q]=head[a],head[a]=q++;} int G[2010][2010],dfn[4010],low[4010],tclock,stk[4010],bel[4010],cnt,top;bool instk[4010]; void dfs(int x){    dfn[x]=low[x]=++tclock;stk[++top]=x,instk[x]=1;    for(int j=head[x];j;j=next[j]){        if(!dfn[end[j]])dfs(end[j]),low[x]=std::min(low[x],low[end[j]]);        else if(instk[end[j]])low[x]=std::min(low[x],dfn[end[j]]);    }    if(dfn[x]==low[x]){        ++cnt;        while(1){            int i=stk[top--];instk[i]=0;            bel[i]=cnt;            if(i==x)break;        }    }} int seq[2010],id; int main(){    int n;Fio::Get(n);register int i,j;    int t,x;for(i=1;i<=n;++i){Fio::Get(t);while(t--)Fio::Get(x),G[i][x]=1,addedge(i,n+x);}     for(i=1;i<=n;++i)Fio::Get(x),addedge(n+x,i);     for(i=1;i<=2*n;++i)if(!dfn[i])dfs(i);     for(i=1;i<=n;++i){        for(id=0,j=1;j<=n;++j)if(bel[i]==bel[n+j]&&G[i][j])seq[++id]=j;        Fio::print(id);        for(j=1;j<=id;++j)Fio::putc(' '),Fio::print(seq[j]);        Fio::putc('\n');        //printf("%d",id);        //for(j=1;j<=id;++j)printf(" %d",seq[j]);        //puts("");    }     Fio::Final(); #ifndef ONLINE_JUDGE    system("pause");#endif    return 0;}</span>

0 0
原创粉丝点击