多校(HDU 7月12日 1009 Equivalent Sets 強連通分支 )

來源:互聯網
上載者:User
 
 Equivalent Sets

Time Limit: 12000/4000 MS (Java/Others)    Memory Limit: 104857/104857 K (Java/Others)
Total Submission(s): 550    Accepted Submission(s): 81

Problem Description
To prove two sets A and B are equivalent, we can first prove A is a subset of B, and then prove B is a subset of A, so finally we got that these two sets are equivalent.You are to prove N sets are equivalent, using the method above: in each step you can prove a set X is a subset of another set Y, and there are also some sets that are already proven to be subsets of some other sets.Now you want to know the minimum steps needed to get the problem proved.
 

Input

The input file contains multiple test cases, in each case, the first line contains two integers N <= 20000 and M <= 50000.Next M lines, each line contains two integers X, Y, means set X in a subset of set Y.
 

Output

For each case, output a single integer: the minimum steps needed.
 

Sample Input

4 03 21 21 3
 

Sample Output

42HintCase 2: First prove set 2 is a subset of set 1 and then prove set 3 is a subset of set 1.
 

Source

HNU

 

我的圖論還處在菜鳥階段,當時比賽的時候看出了是強連通的題,但是tarjon演算法還不會敲,於是在網上找的模板。。。我承認我可恥了。。。

找至少添幾條邊可以使有向圖強連通,縮點之後記錄下出度為零和入度為零的點的個數取最大的就可以了,當然還要特判本身是強連通的,我就因為這個WA了一次,不過也不在乎了,因為本身這題也不會麼。。。 POJ類似題2186 popular cows 也是抄的模板的原題

AC的代碼,應該是別人的代碼:

#include<iostream> 
using namespace std; 
int dfn[20010],low[20010],times,C,s[20010],S[20010],top;    
bool in[20010]; 
struct LIST 

    int v;  LIST *next; 
}; 
 
LIST *head[20010],*rear[20010]; 
 
int chudu[20010],indu[20010]; 
 
void tarjan(int v)      /*tarjan求圖的強連通分量*/ 

    dfn[v]=low[v]=++times; 
    S[top++]=v; 
    in[v]=true; 
    for(LIST *p=head[v];p!=NULL;p=p->next) 
        if(!dfn[p->v]) 
        { 
            tarjan(p->v); 
            if(low[p->v]<low[v]) 
                low[v]=low[p->v]; 
        } 
        else if(in[p->v]&&low[p->v]<low[v]) 
            low[v]=low[p->v]; 
 
    if(low[v]==dfn[v]) 
    { 
        C++; 
        do 
        { 
            v=S[--top]; 
            in[v]=false; 
            s[v]=C;             /*縮圖,標記屬於同一強連通分量的點*/ 
        }while(low[v]!=dfn[v]); 
    } 

 
 
int main() 

    int n,m,i,a,b; 
    while(cin>>n>>m) 
    { 
        memset(head,0,sizeof(int)*20010); 
        memset(rear,0,sizeof(int)*20010); 
        memset(s,0,sizeof(int)*20010); 
        top=0; 
        for(i=0;i<m;i++)         /*鄰接表格儲存體關係圖*/ 
        { 
            scanf("%d%d",&a,&b); 
            if(rear[a]!=NULL) 
            { 
                rear[a]->next=new LIST; 
                rear[a]=rear[a]->next; 
            } 
            else 
                head[a]=rear[a]=new LIST; 
            rear[a]->next=NULL; 
            rear[a]->v=b; 
        } 
        times=0; C=0; 
        memset(dfn,0,sizeof(int)*20010);
        memset(low,0,sizeof(int)*20010);
        memset(in,0,sizeof(bool)); 
        for(i=1;i<=n;i++) 
            if(!dfn[i]) 
                tarjan(i); 
        memset(chudu,0,sizeof(chudu)); 
        memset(indu,0,sizeof(indu));
 
        for(i=1;i<=n;i++)                        /*計算縮圖後每個點的出度*/ 
            for(LIST *p=head[i];p!=NULL;p=p->next) 
                if(s[i]!=s[p->v]) 
                    chudu[s[i]]=1,indu[s[p->v]]=1;
       
        a=b=0; 
        for(i=1;i<=C;i++) 
            if(!chudu[i]) 
                a++; 
        for (i=1 ; i<=C ; i++)
         if(!indu[i])b++;
         if(C==1)printf("0\n");
        //printf("%d %d\n",a,b);
        else
        printf("%d\n",a>b?a:b);
    } 
    return 0; 
 

HNU的解題報告 (依然看不懂)

題目大意:給出一個有向圖,求最少添加多少條邊使得該圖變成強連通圖。

首先如果圖本身就是強連通那麼答案為0。

否則先縮強連通分量將圖變為DAG,然後算出入度為0的點和出度為0的點的個數,取最大值即為答案。

難度:★★

#include <stdio.h>
#include <string.h>

const int MAXN = 20001;
const long MAXM = 50001;

long head[2][MAXN], next[2][MAXM], edge[2][MAXM];
int n;
long m;

int a[MAXN], b[MAXN], c[MAXN];
int k;
long i, j, tot;

void search(const int vtx) {
 b[vtx] = 1;
 for (long i = head[0][vtx]; i; i = next[0][i])
  if (!b[edge[0][i]]) search(edge[0][i]);
 a[++tot] = vtx;
}

void _search(const int vtx) {
 b[vtx] = tot;
 for (long i = head[1][vtx]; i; i = next[1][i])
  if (!b[edge[1][i]]) _search(edge[1][i]);
}

int main() {
while (scanf("%d%ld", &n, &m) == 2) {
 memset(head, 0, sizeof(head));
 for (i = 1; i <= m; ++i) {
  scanf("%ld%d", &j, &k);
  edge[0][i] = k;
  next[0][i] = head[0][j];
  head[0][j] = i;

  edge[1][i] = j;
  next[1][i] = head[1][k];
  head[1][k] = i;
 }

 memset(b, 0, sizeof(b));
 for (tot = 0, i = 1; i <= n; ++i)
  if (!b[i]) search(i);
 memset(b, 0, sizeof(b));
 for (tot = 0, i = n; i; --i)
  if (!b[a[i]]) {
   ++tot;
   _search(a[i]);
  }

 if (tot <= 1) {
  puts("0");
  continue;
 }
 m = tot;
 memset(a, 0, sizeof(a));
 memset(c, 0, sizeof(c));
 for (tot = 0, i = 1; i <= n; ++i)
  for (k = b[i], j = head[0][i]; j; j = next[0][j])
   if (k != b[edge[0][j]]) {
    ++a[b[edge[0][j]]];
    ++c[k];
   }

 for (tot = n = 0, i = 1; i <= m; ++i) {
  if (!a[i]) ++tot;
  if (!c[i]) ++n;
 }
 printf("%ld\n", tot > n ? tot : n);
}
 return 0;
}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.