题意:判断这个图是不是仙人掌:
1、是连通图
2、每条边只属于一个环
如果这个图是仙人掌 , 求出这个图有多少个生成子图是仙人掌
解法:我们用dfs遍历图时 , 如果当前这个点u , 可到达的点中 , 有2个点的low[]或则lowv值 会大于 low[u] ,那么这个图肯定不是仙人掌。
生成图:生成图的点和原图的点一样 , 只有边的数量不一样
那么求原图的生成子图 , 我们只需要删除环中的边(每个环只能删除一条边) , 因此我们只需要求出有多少个环 ,并且我前面我们知道 ,每个环中的边树和点数时相同的
注意:这个题目的答案很大 , 必须要用高精度来计算
代码:
#include
#include
#include
#include
#include
using namespace std;
#define maxn 20010
#define min(x,y) (x)<(y)?(x):(y)
struct node1
{
int x ,y;
}xy;
int low[maxn] , p[maxn];
int n , m , dfs_clock;
int pre[maxn];
int ans[maxn];
int len , cnt;
bool flag;
int bccno[maxn];
vectorgrap[maxn] , bcc[maxn];
stacks;
void init()
{
int i;
memset(pre ,0 , sizeof(pre));
dfs_clock =0;
cnt =0;
for(i = 0; i<= n; i++)
{
bcc[i].clear();
p[i] = i;
}
for(i = 0; i< maxn; i++)
ans[i] =1;
memset(bccno, 0 , sizeof(bccno));
}
int find(int x)
{
int g = x ,h;
while(p[x]!= x)
x = p[x];
while(p[g]!= x)
{
h =p[g];
p[g] =x;
g = h;
}
returnx;
}
void Union(int x , int y)
{
int g =find(x) , h = find(y);
if(g !=h)
p[g] = h;
}
int dfs(int u , int fa)
{
int lowu =low[u] = ++dfs_clock;
int i , lowv, sumcnt = 0;
for(i = 0; i< bcc[u].size(); i++)
{
int v = bcc[u][i];
xy.x = u , xy.y = v;
if(!pre[v])
{
s.push(xy);
pre[v] = 1;
lowv = dfs(v , u);
lowu = min(lowv , lowu);
if(lowv < low[u])
sumcnt++;
if(lowv >= low[u])
{
cnt++;
grap[cnt].clear();
for(;;)
{
node1 gh = s.top();
s.pop();
if(bccno[gh.x] != cnt)
{
grap[cnt].push_back(gh.x) ;
bccno[gh.x] = cnt;
}
if(bccno[gh.y] != cnt)
{
grap[cnt].push_back(gh.y) ;
bccno[gh.y] = cnt;
}
if(gh.x == u &&gh.y == v)
break;
}
}
}
else if(v != fa&& low[v] <low[u])
{
sumcnt++;
s.push(xy);
lowu = min(lowu , low[v]);
}
}
if(sumcnt>= 2)
flag = false;
returnlowu;
}
void bignum(int m)
{ //高精度计算答案
int c =0;
for(int i =0; i < len ; i++)
{
ans[i] =ans[i] * m + c;
c =ans[i]/10;
ans[i] %=10;
}
while(c)
{
ans[len++] =c % 10;
c /=10;
}
}
int main()
{
int tcase =0;
while(scanf("%d %d" , &n , &m) !=EOF)
{
if(tcase++)printf("\n");
int i , j ,k = 0;
int x , y ,z;
init();
for(i = 1; i<= m; i++)
{
scanf("%d" , &z);
if(z != 0)
scanf("%d" ,&x);
for(j = 1; j < z; j++)
{
scanf("%d" , &y);
bcc[x].push_back(y);
bcc[y].push_back(x);
Union(x , y);
x = y;
}
}
x = 0;
for(i = 1; i<= n; i++)
if(p[i] == i)
x += 1;
if(x> 1)
{
cout<<"0"<<endl;
continue;
}
pre[1] =1;
flag =true;
dfs(1 ,-1);
if(!flag)
{
cout<<"0"<<endl;
continue;
}
y = 0;
len =1;
for(i = 1; i<= cnt; i++)
{
x = grap[i].size();
if(x <= 2)
continue;
y = 1;
bignum(x+1);
}
if(!y)
cout<<"1"<<endl;
else
{
for(i = len-1; i >= 0; i--)
cout<<ans[i];
cout<<endl;
}
}
return0;
}
1、是连通图
2、每条边只属于一个环
如果这个图是仙人掌 , 求出这个图有多少个生成子图是仙人掌
解法:我们用dfs遍历图时 , 如果当前这个点u , 可到达的点中 , 有2个点的low[]或则lowv值 会大于 low[u] ,那么这个图肯定不是仙人掌。
生成图:生成图的点和原图的点一样 , 只有边的数量不一样
那么求原图的生成子图 , 我们只需要删除环中的边(每个环只能删除一条边) , 因此我们只需要求出有多少个环 ,并且我前面我们知道 ,每个环中的边树和点数时相同的
注意:这个题目的答案很大 , 必须要用高精度来计算
代码:
#include
#include
#include
#include
#include
using namespace std;
#define maxn 20010
#define min(x,y)
struct node1
{
}xy;
int low[maxn] , p[maxn];
int n , m , dfs_clock;
int pre[maxn];
int ans[maxn];
int len , cnt;
bool flag;
int bccno[maxn];
vectorgrap[maxn] , bcc[maxn];
stacks;
void init()
{
}
int find(int x)
{
}
void Union(int x , int y)
{
}
int dfs(int u , int fa)
{
}
void bignum(int m)
{ //高精度计算答案
}
int main()
{
}