HDU 1269
题意:
如果图中任意两点可以互相到达输出Yes,反之No
解析:
判断强连通分量是否为1
ac:
#include
#define MAXN 100005
using namespace std;
#define inf 0x3f3f3f3f
vector g[MAXN];
int color[MAXN],dfn[MAXN],low[MAXN],stck[MAXN],vis[MAXN];
int deep,top,n,m,sum,a,b;
void tarjan(int u)
{
dfn[u]=++deep;
low[u]=deep;
vis[u]=1;
stck[++top]=u;
int sz=g[u].size();
for(int i=0;i1)
printf("No\n");
else
printf("Yes\n");
}
}
https://vjudge.net/problem/POJ-3177
题意:
给定一个无向连通图,问加多少条边可以使得图变成一个边双连通图
解析:
先求出边双连通,然后缩点,缩点后,将叶子结点相连
结果为:(ans+1)/2;(ans:叶子结点数目)
ac:
#include
#include
#include
#include
#include
#define MAXN 200005
using namespace std;
int to[MAXN<<1],nxt[MAXN<<1],head[MAXN<<1];
int tot,cnt;
int dfn[MAXN],low[MAXN];
int vis[MAXN<<1];
void init()
{
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(vis,0,sizeof(vis));
memset(head,0,sizeof(head));
tot=1,cnt=0;
}
void add(int u,int v)
{
to[++tot]=v;
nxt[tot]=head[u];
head[u]=tot;
}
void tarjan(int x,int fa)
{
dfn[x]=low[x]=++cnt;
for(int i=head[x];i;i=nxt[i])
{
int v=to[i];
if(dfn[v]==0)
{
tarjan(v,i);
low[x]=min(low[x],low[v]);
if(low[v]>dfn[x]){
vis[i]=vis[i^1]=1;
}
}
else if(i!=(fa^1)){
low[x]=min(low[x],dfn[v]);
}
}
}
int u[MAXN<<1],v[MAXN<<1];
vector vc[MAXN];
int c[MAXN],dcc;
void dfs(int x)
{
c[x]=dcc;
for(int i=0;i
https://www.luogu.org/problem/P2341
题意:
将图缩成若干强连通分量
如果一个强连通分量的入度为1,且仅有1个,呢么这个强连通分量里的个数就是答案
ac:
#include
#define MAXN 200005
using namespace std;
int to[MAXN<<1],nxt[MAXN<<1],head[MAXN<<1];
int tot,cnt;
int low[MAXN],dfn[MAXN],vis[MAXN];
stack st;
int stck[MAXN<<1],top;
int c[MAXN],in[MAXN],num;
int sz[MAXN];//对连通分量计数
void init()
{
tot=1;
top=num=cnt=0;
memset(head,0,sizeof(head));
}
void add(int u,int v)
{
to[++tot]=v;
nxt[tot]=head[u];
head[u]=tot;
}
void tarjan(int x)
{
dfn[x]=low[x]=++cnt;
vis[x]=1;
st.push(x);
for(int i=head[x];i;i=nxt[i])
{
int v=to[i];
if(dfn[v]==0)
{
tarjan(v);
low[x]=min(low[x],low[v]);
}
else{
if(vis[v]!=0){
low[x]=min(low[x],dfn[v]);
}
}
}
if(dfn[x]==low[x])
{
int k;
++num;
do{
k=st.top();st.pop();
vis[k]=0;
c[k]=num;
sz[num]++;
}while(x!=k);
}
}
int main()
{
init();
int n,m,u,v;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d",&u,&v),add(u,v);
for(int i=1;i<=n;i++)
{
if(dfn[i]==0)
tarjan(i);
}
for(int i=1;i<=n;i++){//遍历每条边,求每一连通分量的入度
for(int j=head[i];j;j=nxt[j]){
int v=to[j];
if(c[i]!=c[v])
in[c[i]]++;
}
}
int ans=0,tt=0;
for(int i=1;i<=num;i++)//入度为0且数量仅为1
{
if(in[i]==0)
{
tt++;
ans=sz[i];
}
}
if(tt==1)
printf("%d\n",ans);
else
printf("0\n");
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=1827
题意:
他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系过去实在太耗时间和电话费了。
他知道其他人也有一些别人的联系方式,这样他可以通知其他人,再让其他人帮忙通知一下别人。
你能帮Wiskey计算出至少要通知多少人,至少得花多少电话费就能让所有人都被通知到吗?
解析:
我必须通知一些人,这些人打电话给其他人,最后通知了所以人,尽可能的选择必须的且在必须的里选择最小的
对于同一强连通分量,我可以选择里面的任何人,我应该选择里面最小的.
如果一个连通分量能被另外一个连通分量通知,我就不必通知这个连通分量,因为我要通知所以人,所以另一个连通分量应该被先通知.
将图缩点,将同一连通分量缩点,保存同一连通分量里val最小的,然后计算他们的度数,我们选择入度为0,入度为0的只能被我通知
ac:
#include
#define ll long long
#define MAXN 2005
using namespace std;
int to[MAXN<<1],head[MAXN<<1],nxt[MAXN<<1];
int tot;
int val[MAXN];
int dfn[MAXN],low[MAXN],cnt,vis[MAXN];
int c[MAXN];
int in[MAXN];
int com[MAXN],num;
stack sk;
void init()
{
num=cnt=0;
tot=1;
for(int i=0;i