【bzoj2229】[Zjoi2011]最小割

2229: [Zjoi2011]最小割

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 2527  Solved: 898
[Submit][Status][Discuss]

Description

小白在圖論課上學到了一個新的概念——最小割,下課後小白在筆記本上寫下了如下這段話: “對於一個圖,某個對圖中結點的劃分將圖中所有結點分成兩個部分,如果結點s,t不在同一個部分中,則稱這個劃分是關於s,t的割。 對於帶權圖來說,將所有頂點處在不同部分的邊的權值相加所得到的值定義爲這個割的容量,而s,t的最小割指的是在關於s,t的割中容量最小的割” 現給定一張無向圖,小白有若干個形如“圖中有多少對點它們的最小割的容量不超過x呢”的疑問,小藍雖然很想回答這些問題,但小藍最近忙着挖木塊,於是作爲仍然是小藍的好友,你又有任務了。

Input

輸入文件第一行有且只有一個正整數T,表示測試數據的組數。 對於每組測試數據, 第一行包含兩個整數n,m,表示圖的點數和邊數。 下面m行,每行3個正整數u,v,c(1<=u,v<=n,0<=c<=106),表示有一條權爲c的無向邊(u,v) 接下來一行,包含一個整數q,表示詢問的個數 下面q行,每行一個整數x,其含義同題目描述。

Output

對於每組測試數據,輸出應包括q行,第i行表示第i個問題的答案。對於點對(p,q)和(q,p),只統計一次(見樣例)。

兩組測試數據之間用空行隔開。

Sample Input

1
5 0
1
0

Sample Output

10

【數據範圍】
對於100%的數據 T<=10,n<=150,m<=3000,q<=30,x在32位有符號整數類型範圍內。
圖中兩個點之間可能有多條邊

HINT

Source

[Submit][Status][Discuss]


最小割樹模板題系列


代碼:
#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<algorithm>
#include<cstdlib>
#include<stack>
#include<cstring>
#include<cmath>
using namespace std;

typedef long long LL;

const int INF = 2147483647;
const int maxm = 30000;
const int maxn = 160;

struct edge{
	int to,cap,flow;
}e[maxm];

struct data{
	int to,w;
};

vector<int> G[maxn];
vector<data> p[maxn];
int n,m,s,t,N,now,tot,ans;
int dis[maxn],Q[maxn],cur[maxn],vis[maxn];
int fa[maxn],faw[maxn],Vis[maxn];

inline LL getint()
{
	LL ret = 0,f = 1;
	char c = getchar();
	while (c < '0' || c > '9')
	{
		if (c == '-') f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
		ret = ret * 10 + c - '0',c = getchar();
	return ret * f;
}

inline bool bfs()
{
	memset(dis,-1,sizeof(dis));
	memset(cur,0,sizeof(cur));
	int head = 0,tail = 0;
	Q[++tail] = s; dis[s] = 0;
	++now;
	while (head < tail)
	{
		int u = Q[++head];
		vis[u] = now;
		for (int i = 0; i < G[u].size(); i++)
		{
			edge E = e[G[u][i]];
			if (dis[E.to] != -1 || E.flow == E.cap) continue;
			dis[E.to] = dis[u] + 1;
			
			Q[++tail] = E.to;
		}
	}
	return dis[t] != -1;
}

inline int dinic(int u,int a)
{
	if (!a || u == t) return a;
	int flow = 0;
	for (int &i = cur[u]; i < G[u].size(); i++)
	{
		edge &E = e[G[u][i]];
		if (E.flow == E.cap || dis[E.to] != dis[u] + 1) continue;
		int f = dinic(E.to,min(a,E.cap - E.flow));
		E.flow += f;
		flow += f;
		a -= f;
		e[G[u][i] ^ 1].flow -= f;
		if (!a) break;
	}
	return flow;
}

inline void init()
{
	for (int i = 0; i <= tot; i += 2) e[i].flow = 0;
	for (int i = 1; i <= tot; i += 2) e[i].flow = e[i].cap;
}

inline int maxflow(int S,int T)
{
	init();
	int ret = 0;
	s = S; t = T;
	while (bfs()) 
		ret += dinic(s,INF);
	return ret;
}

inline void add(int u,int v,int cap)
{
	e[++tot] = (edge){v,cap,0};
	G[u].push_back(tot);
	e[++tot] = (edge){u,cap,cap};
	G[v].push_back(tot);
}

inline int dfs(int u,int a,int cap)
{
	int ret = 0;
	Vis[u] = 1;
	if (a <= cap) ret++;
	for (int i = 0; i < p[u].size(); i++)
	{
		int v = p[u][i].to,w = p[u][i].w;
		if (Vis[v]) continue;
		ret += dfs(v,min(a,w),cap);
	}
	return ret;
}

int main()
{
	int test = getint();
	while (test--)
	{
		now = 0; tot = -1;
		memset(e,0,sizeof(e));
		memset(vis,0,sizeof(vis));
		n = getint(); m = getint();
		for (int i = 1; i <= n; i++) G[i].clear();
		for (int i = 1; i <= m; i++)
		{
			int u = getint(),v = getint(),w = getint();
			add(u,v,w); add(v,u,w);
		}
		for (int i = 2; i <= n; i++) fa[i] = 1;
		for (int i = 2; i <= n; i++)
		{
			faw[i] = maxflow(i,fa[i]);
			for (int j = i + 1; j <= n; j++)
				if (fa[i] == fa[j] && vis[i] == vis[j])
					fa[j] = i;
		}
		int q = getint();
		for (int i = 1; i <= n; i++) p[i].clear();
		for (int i = 2; i <= n; i++)
		{
			p[i].push_back((data){fa[i],faw[i]});
			p[fa[i]].push_back((data){i,faw[i]});
		}
		for (int j = 1; j <= q; j++)
		{
			int c = getint();
			ans = 0;
			for (int i = 1; i <= n; i++) 
			{
				memset(Vis,0,sizeof(Vis));
				ans += dfs(i,INF,c);
			}
			printf("%d\n",ans >> 1);
		}
		putchar('\n');
	}
	return 0;
}

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