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; }
思路:n^2枚举
代码:
#include<cstdio> #include<iostream> #include<vector> #include<cstring> #include<algorithm> #define MAX_N 5555 using 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; }
题意:
思路:缩点后形成一棵树,加边后成环,环内所有的边都会变成非桥边 标记去重 减去即可。
代码:
<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>
题意:
思路:奇怪的二分图+强连通分量 不会。
代码:
<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>