应用图的ADT的物理实现来解决图的应用问题。
某国的军队由N个部门组成,为了提高安全性,部门之间建立了M条通路,每条通路只能单向传递信息,即一条从部门a到部门b的通路只能由a向b传递信息。信息可以通过中转的方式进行传递,即如果a能将信息传递到b,b又能将信息传递到c,则a能将信息传递到c。一条信息可能通过多次中转最终到达目的地。
由于保密工作做得很好,并不是所有部门之间都互相知道彼此的存在。只有当两个部门之间可以直接或间接传递信息时,他们才彼此知道对方的存在。部门之间不会把自己知道哪些部门告诉其他部门。
上图中给了一个4个部门的例子,图中的单向边表示通路。部门1可以将消息发送给所有部门,部门4可以接收所有部门的消息,所以部门1和部门4知道所有其他部门的存在。部门2和部门3之间没有任何方式可以发送消息,所以部门2和部门3互相不知道彼此的存在。
现在请问,有多少个部门知道所有N个部门的存在。或者说,有多少个部门所知道的部门数量(包括自己)正好是N。
【输入形式】
输入的第一行包含两个整数N, M,分别表示部门的数量和单向通路的数量。所有部门从1到N标号。
接下来M行,每行两个整数a, b,表示部门a到部门b有一条单向通路。
【输出形式】
输出一行,包含一个整数,表示答案。
【样例输入】
4 4
1 2
1 3
2 4
3 4
【样例输出】
2
【样例说明】
部门1和部门4知道所有其他部门的存在。
【评测用例规模与约定】
所有的评测用例,1 ≤ N ≤ 10,1 ≤ M ≤ 20;
#ifndef Graph_h
#define Graph_h
#include <stdio.h>
template <typename VertexType>
class Graph
{
private:
void operator=(const Graph&) {} // Protect assignment
Graph(const Graph &) {} // Protect copy constructor
public:
Graph(){}
virtual ~Graph() {}
virtual void Init(int n) =0;
//return thr number of vertices and edges
virtual int n() =0;
virtual int e() =0;
// Return v's first neighbor
virtual int first(int v) =0;
// Return v's next neighbor
virtual int next(int v, int w) =0;
virtual void setType(bool flag)=0;
virtual bool getType()=0;
virtual int locateVex(VertexType u) =0;
virtual VertexType getVex(int v)=0;
virtual void putVex(int v,VertexType value) =0;
// Set the weight for an edge (v1,v2)
virtual void setEdge(int v1, int v2, int wght) =0;
// Delete an edge
virtual void delEdge(int v1, int v2) =0;
virtual bool isEdge(int i, int j) =0;
virtual int weight(int v1, int v2) =0;
// Get and Set the mark value for a vertex
virtual int getMark(int v) =0;
virtual void setMark(int v, int val) =0;
virtual void DFS(int v)=0;
virtual void BFS(int v)=0;
};
#endif
#ifndef Graphl_h
#define Graphl_h
#include "Link.h"
#include "LList.h"
#include "Graph.h"
#include <queue>
#define MAX_VERTEX_NUM 40
#define UNVISITED 0
#define VISITED 1
#define ERROR -1
// Edge class for Adjacency List graph representation
class Edge
{
private:
int vert, wt;
public:
Edge() { vert = -1; wt = -1; }
Edge(int v, int w) { vert = v; wt = w; }
int vertex() { return vert; }
int weight() { return wt; }
};
// Overload for the Edge << operator
/*ostream& operator << (ostream& s, Edge e)
{
return s << "(" << e.vertex() << ", " << e.weight() << ")";
}*/
template <typename VertexType>
class Graphl : public Graph<VertexType>
{
private:
LList<Edge>** vertex; // List headers
int numVertex, numEdge;
int *mark; // Pointer to mark array
bool undirected;
VertexType vexs[MAX_VERTEX_NUM];
public:
int Out(int i)
{
return vertex[i]->length();
}
Graphl(int numVert) { Init(numVert); }
Graphl()
{
delete [] mark; // Return dynamically allocated memory
for (int i=0; i<numVertex; i++)
delete [] vertex[i];
delete [] vertex;
}
void Init(int n)
{
int i;
numVertex = n;
numEdge = 0;
mark = new int[n];
for (i=0; i<numVertex; i++)
mark[i] = UNVISITED;
vertex =new LList<Edge>*[numVertex];
for (i=0; i<numVertex; i++)
vertex[i] = new LList<Edge>();
}
int n() { return numVertex; }
int e() { return numEdge; }
int first(int v)
{ // Return first neighbor of "v"
if (vertex[v]->length()==0)
return numVertex; // No neighbor
vertex[v]->moveToStart();
Edge it = vertex[v]->getValue();
return it.vertex();
}
// Get v's next neighbor after w
int next(int v, int w)
{
Edge it;
if(isEdge(v,w))
{
if ((vertex[v]->currPos()+1)<vertex[v]->length())
{
vertex[v]->next();
it = vertex[v]->getValue();
return it.vertex();
}
}
return n(); // No neighbor
}
void setType(bool flag)
{
undirected=flag;
}
bool getType(){ return undirected;}
int locateVex(VertexType u)
{
for(int i=0;i<numVertex;i++)
{
if(u==vexs[i])
return i;
}
return -1;
}
VertexType getVex(int v) {return vexs[v];}
void putVex(int v,VertexType value) {vexs[v]=value;}
// Set edge (i, j) to "weight"
void setEdge(int i, int j, int weight)
{
if(weight<=0)
{
cout<<"May not set weight to 0\n";
return ;
}
Edge currEdge(j, weight);
if (isEdge(i, j))
{ // Edge already exists in graph
vertex[i]->remove();
vertex[i]->insert(currEdge);
}
else
{ // Keep neighbors sorted by vertex index
numEdge++;
for (vertex[i]->moveToStart();vertex[i]->currPos() < vertex[i]->length();vertex[i]->next())
{
Edge temp = vertex[i]->getValue();
if (temp.vertex() >j) break;
}
vertex[i]->insert(currEdge);
if(undirected)
{
Edge currEdge(i, weight);
for (vertex[j]->moveToStart();vertex[j]->currPos() < vertex[j]->length();vertex[j]->next())
{
Edge temp = vertex[j]->getValue();
if (temp.vertex() > i) break;
}
vertex[j]->insert(currEdge);
}
}
}
void delEdge(int i, int j)
{
if (isEdge(i,j))
{
vertex[i]->remove();
numEdge--;
}
if(undirected)
{
if (isEdge(j,i))
{
vertex[j]->remove();
numEdge--;
}
}
}
bool isEdge(int i, int j)
{
Edge it;
for (vertex[i]->moveToStart();vertex[i]->currPos() < vertex[i]->length();vertex[i]->next())
{ // Check whole list
Edge temp = vertex[i]->getValue();
if (temp.vertex() ==j) return true;
}
return false;
}
int weight(int i, int j)
{ // Return weight of (i, j)
Edge curr;
if (isEdge(i, j))
{
curr = vertex[i]->getValue();
return curr.weight();
}
else return 0;
}
int getMark(int v) { return mark[v]; }
void setMark(int v, int val) { mark[v] = val; }
void DFS(int v)
{
setMark(v,VISITED);
cout<<getVex(v)<<' ';
for(int i=first(v);i<n();i=next(v,i))
{
if(getMark(i)==UNVISITED)
{
DFS(i);
}
}
}
void BFS(int v)
{
queue<int> q;
setMark(v,VISITED);
//cout<<getVex(v)<<' ';
q.push(v);
while(!q.empty())
{
v=q.front();
q.pop();
for(int i=first(v);i<n();i=next(v,i))
{
if(getMark(i)==UNVISITED)
{
setMark(i,VISITED);
//cout<<getVex(i)<<' ';
q.push(i);
}
}
}
//cout<<endl;
}
};
#endif
#ifndef Link_h
#define Link_h
#include <iostream>
template <typename E> class Link
{
public:
E element;
Link *next;
Link(const E& elemval, Link* nextval =NULL)
{
element = elemval;
next = nextval;
}
Link(Link* nextval =NULL)
{ next = nextval; }
};
#endif
#ifndef LList_h
#define LList_h
#include "Link.h"
#include "List.h"
#include<iostream>
using namespace std;
template <typename E> class LList: public List<E>
{
private:
Link<E>* head;
Link<E>* tail;
Link<E>* curr;
int cnt;
void init()
{
curr = tail = head = new Link<E>;
cnt = 0;
}
void removeall()
{
// Return link nodes to free store
while(head != NULL)
{
curr = head;
head = head->next;
delete curr;
}
}
public:
LList(int size=100) { init(); }
~LList() { removeall(); }
void clear() { removeall(); init(); }
void insert(const E& it)
{
curr->next = new Link<E>(it, curr->next);
if (tail == curr)
tail = curr->next;
cnt++;
}
void append(const E& it)
{
tail = tail->next = new Link<E>(it, NULL);
cnt++;
}
E remove()
{
if(curr->next==NULL)
return curr->element;;
E it = curr->next->element;
Link<E>* ltemp = curr->next;
if (tail == curr->next)
tail = curr;
curr->next = curr->next->next;
delete ltemp;
cnt--;
return it;
}
void moveToStart() { curr = head; }
void moveToEnd(){ curr = tail; }
void prev()
{
if (curr == head) return;
Link<E>* temp = head;
// March down list until we find the previous element
while (temp->next!=curr) temp=temp->next;
curr = temp;
}
void next()
{
if (curr != tail)
curr = curr->next;
}
int length() const { return cnt; }
int currPos() const
{
Link<E>* temp = head;
int i;
for (i=0; curr != temp; i++)
temp = temp->next;
return i;
}
void moveToPos(int pos)
{
if ((pos>=0)&&(pos<=cnt))//"Position out of range"
{
curr = head;
for(int i=0; i<pos; i++) curr = curr->next;
}
}
const E& getValue() const
{
return curr->next->element;
}
const E& getNo() const
{
return curr->next->No;
}
const E& getCode() const
{
return curr->next->Code;
}
void reverse()
{
// Reverse list contents
if(head->next == NULL) return;
// First, fix fence by pushing it forward one step
//if (fence->next == NULL)
// fence = head;
//else fence = fence->next;
// Now, reverse the list
Link<E>* temp1 = head->next;
Link<E>* temp2 = temp1->next;
while (temp2 != NULL)
{
Link<E>* temp3 = temp2->next;
temp2->next = temp1;
temp1 = temp2;
temp2 = temp3;
cout<<endl;
}
head->next->next=NULL;
head->next = temp1;
}
};
#endif
#ifndef List_h
#define List_h
template <typename E> class List { // List ADT
private:
void operator =(const List&) {} // Protect assignment
List(const List&) {} // Protect copy constructor
public:
List() {}
virtual ~List() {} // Base destructor
virtual void clear() = 0;
virtual void insert(const E& item) = 0;
// Append an element at the end of the list.
virtual void append(const E& item) = 0;
virtual E remove() = 0;
// Set the current position to the start of the list.
virtual void moveToStart() = 0;
// Set the current position to the end of the list.
virtual void moveToEnd() = 0;
virtual void prev() = 0;
virtual void next() = 0;
virtual int length() const = 0;
// Return: The position of the current element.
virtual int currPos() const = 0;
virtual void moveToPos(int pos) = 0;
// Return: The current element.
virtual const E& getValue() const = 0;
};
#endif
#include <iostream>
#include "Graph.h"
#include "Graphl.h"
using namespace std;
int main( )
{
int n,m,i,j;
cin>>n>>m;
Graphl<int> G(n);
G.setType(0);
for(i=0;i<n;i++)
G.putVex(i,i+1);
int u,v;
for(i=0;i<m;i++)
{
cin>>u>>v;
G.setEdge(u-1,v-1,1);
}
int a[n][n];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
a[i][j]=0;
for(i=0;i<n;i++)
{
G.BFS(i);
for(j=0;j<n;j++)
{
if(G.getMark(j)==VISITED)
{
a[i][j]=1;
a[j][i]=1;
}
}
for(j=0;j<G.n();j++)
{
G.setMark(j,UNVISITED);
}
}
int sum=0;
for(i=0;i<n;i++)
{
int flag=1;
for(j=0;j<n;j++)
{
if(a[i][j]==0)
{
flag=0;
break;
}
}
if(flag)
sum++;
}
cout<<sum<<endl;
return 0;
}