poj 2793 有难度的点连通分量应用

来源:互联网 发布:淘宝运送方式怎么设置 编辑:程序博客网 时间:2024/06/03 03:11
题意:判断这个图是不是仙人掌:
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;
}

0 0
原创粉丝点击