hdu2767——強連通結合入點和出點爲0的性質

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=2767

Consider the following exercise, found in a generic linear algebra textbook.

Let A be an n × n matrix. Prove that the following statements are equivalent:

1. A is invertible.
2. Ax = b has exactly one solution for every n × 1 matrix b.
3. Ax = b is consistent for every n × 1 matrix b.
4. Ax = 0 has only the trivial solution x = 0.

The typical way to solve such an exercise is to show a series of implications. For instance, one can proceed by showing that (a) implies (b), that (b) implies (c), that (c) implies (d), and finally that (d) implies (a). These four implications show that the four statements are equivalent.

Another way would be to show that (a) is equivalent to (b) (by proving that (a) implies (b) and that (b) implies (a)), that (b) is equivalent to (c), and that (c) is equivalent to (d). However, this way requires proving six implications, which is clearly a lot more work than just proving four implications!

I have been given some similar tasks, and have already started proving some implications. Now I wonder, how many more implications do I have to prove? Can you help me determine this?

Input

On the first line one positive number: the number of testcases, at most 100. After that per testcase:

* One line containing two integers n (1 ≤ n ≤ 20000) and m (0 ≤ m ≤ 50000): the number of statements and the number of implications that have already been proved.
* m lines with two integers s1 and s2 (1 ≤ s1, s2 ≤ n and s1 ≠ s2) each, indicating that it has been proved that statement s1 implies statement s2.

Output

Per testcase:

* One line with the minimum number of additional implications that need to be proved in order to prove that all statements are equivalent.

Sample Input

2
4 0
3 2
1 2
1 3

Sample Output

4
2

題目翻譯:

考慮下面的練習,在一般線性代數教科書中找到。

設A爲N×N矩陣。證明以下陳述是等效的:

1。A是可逆的。              

2。ax=b每N×1矩陣b只有一個解。              

3。每個n×1矩陣b的ax=b是一致的。              

4。ax=0只有平凡解x=0。

解決這類問題的典型方法是展示一系列含義。例如,可以繼續顯示(a)暗示(b),表示(b)暗示(c),表示(c)暗示(d),最後表示(d)暗示(a)。這四個含義表明這四個語句是等價的。

另一種方法是證明(a)等同於(b)(通過證明(a)意味着(b)和(b)意味着(a),(b)等同於(c),(c)等同於(d)。然而,這種方法需要證明六個含義,這顯然比證明四個含義要多得多!

我被賦予了一些類似的任務,並且已經開始證明一些含義。現在我想知道,我還需要證明多少含義?你能幫我確定嗎?

輸入

 在第一行,一個正數:測試用例的數量,最多100個。之後每個測試用例:

*一行包含兩個整數n(1≤n≤20000)和m(0≤m≤50000):語句數和已經證明的含義數。        

*m兩個整數分別爲s1和s2(1≤s1,s2≤n和s1≠s2)的行,表示已經證明語句s1表示語句s2。 

 輸出

每個測試用例:

 *爲了證明所有語句都是等價的,需要證明的附加含義最少的一行。 

很經典的一道強連通題,首先需要縮點,之後用到了入度爲0和出度爲0點的性質。

劉汝佳的白書裏面也有這道題。

#include <iostream>
#include<vector>
#include<cstdio>
#include<stack> 
using namespace std;
const int maxn=1e5+7;
int pre[maxn],low[maxn],sccno[maxn],dfs_clock,scc_cnt;
int in0[maxn],out0[maxn];
stack<int> s;
vector<int> G[maxn];
int n,m;
void dfs(int u){
	pre[u]=low[n]=++dfs_clock;
	s.push(u);
	for(int i = 0;i<(int)G[u].size();++i){
		int v=G[u][i];
		if(!pre[v]){
			dfs(v);
			low[u]=min(low[u],low[v]);
		}
		else if(!sccno[v]){
			low[u]=min(low[u],pre[v]); 
		}
	}
	if(low[u]==pre[u]){
		scc_cnt++;
		while(1){
			int x=s.top();
			s.pop();
			sccno[x]=scc_cnt;
			if(x==u) break;
		}
	}
}
void find_scc(int n){
	dfs_clock=scc_cnt=0;
	memset(pre,0,sizeof(pre));
	memset(sccno,0,sizeof(pre));
	for(int i = 0;i<n;++i)
		if(!pre[i])
			dfs(i);
}
int main(int argc, char** argv) {
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		for(int i = 0;i<n;++i) G[i].clear();
		for(int i = 0;i<m;++i){
			int x,y;
			scanf("%d%d",&x,&y);
			x--,y--;
			G[x].push_back(y);
		}
		find_scc(n);
		printf("%d\n",scc_cnt);
		for(int i = 1;i<=scc_cnt;++i) in0[i]=out0[i]=1;
		for(int u = 0;u<n;++u){
			for(int i = 0;i<(int)G[u].size();++i){
				int v=G[u][i];
				if(sccno[u]!=sccno[v]) out0[sccno[v]]=in0[sccno[u]]=0;
			}
		}
		int a=0,b=0;
		for(int i = 1;i<=scc_cnt;++i){
			if(in0[i]) a++;
			if(out0[i]) b++;
		}
		if(scc_cnt==1)	printf("0\n");
		else	printf("%d\n",max(a,b));
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章