poj 2186 Popular Cows(Kosaraju + 变形)

感想详见:http://blog.csdn.net/zxy_snow/archive/2011/01/18/6149058.aspx

 

我用了两种做法。

 

Kosaraju 缩点后加DFS,搜索能满足题意的点,也就是缩点后集合能到达其他任意集合的点。1800+MS。

 

Kosaraju 缩点后查找入度为0的点,如果只有1个,那么这个肯定就是答案。250MS。

 

可以证明一下,如果没有入度为0的点,那么缩点肯定是一个环,这样的话,求强连通分量的时候,肯定是当成一个求的,就不会分这么多个。

 

如果入度为0的点不为1,那么肯定有不能到达的缩点,那么肯定这个集合的缩点都不能被其他的缩点到达,所以肯定这个集合的cows不喜欢其他的cows。

 

呃。我的缩点是在转置后的邻接表基础上建成的。

 

如果是转置前的,需要找出度为0的点。

 

DFS

 

#include <stdio.h> #include <stdlib.h> #include <iostream> #include <string.h> #include <stack> #define MAX 10010 using namespace std; typedef struct cow{ int to; cow *next; }cow; typedef struct shrdot{ int num,head; shrdot *next; }shrdot; shrdot *shr[MAX],mall[MAX*5]; cow *c[MAX],*ce[MAX],node[MAX*10]; stack <int> fin; int n,m,cou,sou,ind,sum; int visit[MAX],pre[MAX],tmp[MAX],used[MAX]; void init() { memset(c,'/0',sizeof(c)); memset(ce,'/0',sizeof(ce)); memset(node,'/0',sizeof(node)); memset(mall,'/0',sizeof(mall)); memset(shr,'/0',sizeof(shr)); cou = 0; } void input() { int from,to; scanf("%d%d",&n,&m); while(m--) { scanf("%d%d",&from,&to); node[cou].to = to; node[cou].next = c[from]; c[from] = &node[cou++]; } } void Transpose(cow **c,cow **ce) { int i; cow *head; for(i=1; i<=n; i++) { head = c[i]; while( head != NULL ) { node[cou].to = i; node[cou].next = ce[head->to]; ce[head->to] = &node[cou++]; head = head->next; } } } void FirDFS(cow **c,int s) { visit[s] = 1; cow *head = c[s]; while( head != NULL ) { if( !visit[head->to] ) FirDFS(c,head->to); head = head->next; } fin.push(s); } void SecDFS(cow **ce,int s,int ss) { visit[s] = 1; cow *head = ce[s]; while( head != NULL ) { if( !visit[head->to] ) { sou++; pre[head->to] = ss; SecDFS(ce,head->to,ss); } else tmp[ind++] = head->to; head = head->next; } } void ShrDFS(int s) { visit[s] = 1; shrdot *head = shr[s]; while( head != NULL ) { if( !visit[head->head] ) { sum += shr[head->head]->num; ShrDFS(head->head); } head = head->next; } } void Kosaraju(cow **c, cow **ce) { int i,num,k,ans; Transpose(c,ce); memset(visit,0,sizeof(visit)); for(i=1; i<=n; i++) if( c[i] != NULL && !visit[i] ) FirDFS(c,i); memset(visit,0,sizeof(visit)); memset(pre,0,sizeof(pre)); int shrcou = 0,jilu = 0; while( !fin.empty() ) { num = fin.top(); fin.pop(); ind = 0; sou = 1; memset(used,0,sizeof(used)); if( !visit[num] ) { pre[num] = shrcou; SecDFS(ce,num,shrcou); mall[jilu].num = sou; mall[jilu].head = shrcou; mall[jilu].next = shr[shrcou]; shr[shrcou] = &mall[jilu++]; for(i=0; i<ind; i++) if( tmp[i] != num && pre[tmp[i]] != shrcou && !used[pre[tmp[i]]] ) { mall[jilu].num = shr[pre[tmp[i]]]->num; mall[jilu].head = shr[pre[tmp[i]]]->head; mall[jilu].next = shr[shrcou]->next; shr[shrcou]->next = &mall[jilu++]; used[pre[tmp[i]]] = 1; } shrcou++; } } ans = 0; for(i=0; i<shrcou; i++)// 第三个DFS,搜满足题意的缩点。 { sum = shr[i]->num; memset(visit,0,sizeof(visit)); ShrDFS(i); if( sum == n ) ans += shr[i]->num; } printf("%d/n",ans); } int main() { init(); input(); Kosaraju(c,ce); return 0; }  

 

找入度

 

#include <stdio.h> #include <stdlib.h> #include <iostream> #include <string.h> #include <stack> #define MAX 10010 using namespace std; typedef struct cow{ int to; cow *next; }cow; cow *c[MAX],*ce[MAX],node[MAX*10]; stack <int> fin; int n,m,cou,sou,ind,sum; int visit[MAX],pre[MAX],tmp[MAX],used[MAX]; void init() { memset(c,'/0',sizeof(c)); memset(ce,'/0',sizeof(ce)); memset(node,'/0',sizeof(node)); cou = 0; } void input() { int from,to; scanf("%d%d",&n,&m); while(m--) { scanf("%d%d",&from,&to); node[cou].to = to; node[cou].next = c[from]; c[from] = &node[cou++]; } } void Transpose(cow **c,cow **ce) { int i; cow *head; for(i=1; i<=n; i++) { head = c[i]; while( head != NULL ) { node[cou].to = i; node[cou].next = ce[head->to]; ce[head->to] = &node[cou++]; head = head->next; } } } void FirDFS(cow **c,int s) { visit[s] = 1; cow *head = c[s]; while( head != NULL ) { if( !visit[head->to] ) FirDFS(c,head->to); head = head->next; } fin.push(s); } void SecDFS(cow **ce,int s,int ss) { visit[s] = 1; cow *head = ce[s]; while( head != NULL ) { if( !visit[head->to] ) { sou++; pre[head->to] = ss; SecDFS(ce,head->to,ss); } else tmp[ind++] = head->to; head = head->next; } } void Kosaraju(cow **c, cow **ce) { int i,num,count,tmpi; int in[MAX],setn[MAX]; Transpose(c,ce); memset(visit,0,sizeof(visit)); for(i=1; i<=n; i++) if( c[i] != NULL && !visit[i] ) FirDFS(c,i); memset(visit,0,sizeof(visit)); memset(pre,0,sizeof(pre)); memset(in,0,sizeof(in)); memset(setn,0,sizeof(setn)); while( !fin.empty() ) { num = fin.top(); fin.pop(); ind = 0; sou = 1; memset(used,0,sizeof(used)); if( !visit[num] ) { pre[num] = num; SecDFS(ce,num,num); setn[num] = sou; used[num] = 1; for(i=0; i<ind; i++) if( !used[pre[tmp[i]]] ) { in[pre[tmp[i]]]++; //记录点的入度。 used[pre[tmp[i]]] = 1; } } } for(i=1; i<=n; i++)//如果有点一直没有被访问到,肯定是单独的点,输出0 if( !visit[i] ) { printf("0/n"); return ; } count = 0; for(i=1; i<=n; i++) if( pre[i] == i && in[i] == 0 ) //找入度为0的点 { tmpi = i; count++; } if( count == 1 ) // 如果入度为0的点只有一个,那么肯定就是满足题意的,其他都不对。 printf("%d/n",setn[tmpi]); else printf("0/n"); } int main() { init(); input(); Kosaraju(c,ce); return 0; }  

你可能感兴趣的:(c,struct,null,input)