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 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;
}
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>