hdu 4635(強連通分量)

題目鏈接

不難得到如下結論:如果原圖不是強連通, 那麼最優解肯定是隻剩兩個強連通分量且每個分量內都爲完全圖, 可以列出數學表達式不難

發現最後的結果只和兩個分量中的點數的乘積有關, 由於兩者的和一定使兩者的差儘可能大, 但一個點如果既有出度又有入度就不能單

獨將它作爲最後的一個點, 所以我要考慮只有出度或者入度的點。


#include <iostream>
#include <stack>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <vector>
#include <cmath>

using namespace std;

typedef long long LL;

const int N = 100005;
const int M = N << 4;


struct SCC {
	struct Edge {
		int v;
		Edge* next;

		void init(int a, Edge* e) {
			v = a, next = e;
		}
	};

	Edge E[M], * head[N];
	int low[N], pre[N], no[N];
	int cnt[N];
	int n, tot, sum, tdfn, m;
	int in[N], out[N];
	stack<int> stk;

	void init(int n, int m) {
		this->n = n;
		this->m = m;
		for (int i = 0; i < n; i++) {
			head[i] = 0;
			no[i] = -1;
			pre[i] = 0;
			cnt[i] = 0;
		}
		tot = 0, sum = 0, tdfn = 0;
	}

	void add(int u, int v) {
		E[tot].init(v, head[u]);
		head[u] = &E[tot++];
	}

	void dfs(int u) {
		pre[u] = low[u] = ++tdfn;
		stk.push(u);

		for (Edge* e = head[u]; e; e = e->next) {
			int v =	e->v;
			if (!pre[v]) {
				dfs(v);
				low[u] = min(low[u], low[v]);
			}
			else if (no[v] == -1)
				low[u] = min(low[u], pre[v]);
		}

		if (low[u] == pre[u]) {
			sum++;
			while(1) {
				int x = stk.top();
				stk.pop();
				no[x] = sum - 1;
				if (x == u) break;
			}
		}
	}

	LL run() {
		for (int i = 0; i < n; i++)
			if (pre[i] == 0)
				dfs(i);
		
		if (sum == 1) return -1;

		int key = N;

		for (int i = 0; i < n; i++) {
			cnt[no[i]]++;	
		}

		for (int i = 0; i < sum; i++)
			in[i] = 0, out[i] = 0;

		for (int i = 0; i < n; i++)
			for (Edge* e = head[i]; e; e = e->next) {
				int v = e->v;
				if (no[i] == no[v]) continue;
				in[no[v]]++;
				out[no[i]]++;			
			}

		for (int i = 0; i < sum; i++) {
			if (in[i] && out[i]) continue;
			key = min(key, cnt[i]);
		}

		LL res = (LL) n * n - n - m - (LL)key * (n - key);

		return res;
				
	}
}G;

int main() {
	int test, u, v, n, m;
	scanf("%d", &test);
	int cas = 1;
	while (test--) {
		scanf("%d%d", &n, &m);
		G.init(n, m);
		for (int i = 0; i < m; i++) {
			scanf("%d%d", &u, &v);
			u--, v--;
			G.add(u, v);
		}
		cout << "Case " << cas++ << ": " << G.run() << endl;
	}	
	return 0;
}

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