伤不起的 强连通+二分匹配 hdu 3861

这么裸的两个算法综合竟然错了15把 敲打,重新写了一遍 ,终于A了,伤不起啊.....
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<math.h>
#include <vector>
using namespace std;

#define MAXN 100010
//强连通
vector<int>mat[MAXN];原图
int id[MAXN/2], pre[MAXN/2];
int low[MAXN/2], s[MAXN/2];
int stop, cnt, scnt;

void tarjan(int v, int n){
	int t, minc = low[v] = pre[v] = cnt++;
	vector<int>::iterator pv;
	s[stop++] = v;
	for (pv = mat[v].begin(); pv != mat[v].end(); ++pv){
		if (-1 == pre[*pv])
			tarjan(*pv, n);
			if (low[*pv] < minc)
				minc = low[*pv];
	}

	if (minc < low[v]){
		low[v] = minc;
		return;
	}

	do{
		id[t = s[--stop]] = scnt;
		low[t] = n;
	}while (t != v);
	++scnt;
}


/二分匹配/
vector<int>new_mat[MAXN];//新图
bool flag[MAXN];
int qian[MAXN];

bool dfs(int u){
	for (int i = 0; i < new_mat[u].size(); i++){
		int v = new_mat[u][i];
		if (flag[v])
		continue;
		flag[v] = 1;
		if (qian[v] == -1 || dfs(qian[v])){
			qian[v] = u;
			return true;
		}
	}
	return false;
}

int MaxMatch(){
	int i , ans = 0;
	memset(qian, -1, sizeof(qian));
	for (i = 0; i < scnt; i++){
		memset(flag, false, sizeof(flag));
		if (dfs(i))
			ans++;
	}
	return ans;
}
///

int UU[MAXN], VV[MAXN];

int main()
{
	int T;
	int n, m;

	scanf("%d", &T);
	while (T--){
		scanf("%d%d", &n, &m);

		for (int i = 0; i <= n; i++)
			mat[i].clear();

		for (int i = 0; i < m; i++){
			scanf("%d%d", &UU[i], &VV[i]);
			UU[i]--;
			VV[i]--;
			mat[UU[i]].push_back(VV[i]);
		}

		//强连通///
		stop = cnt = scnt = 0;
		memset(pre, -1, sizeof(pre));

		for (int i = 0; i < n; i++){
			if (-1 == pre[i])
				tarjan(i, n);
		}

		if (scnt == 1){
			printf("1\n");
			continue;
		}
		/*///
		printf("每个点所属的强连通编号: ");
		for (int i = 0; i < n; i++)
			printf("%d = %d ", i, id[i]);
		printf("\n");
		///*/

		二分匹配/
		/*建图*/
		for (int i = 0; i < scnt*2; i++)
			new_mat[i].clear();

		for (int i = 0; i < m; i++){
			int fa_u = id[UU[i]];
			int fa_v = id[VV[i]];
			if (fa_u != fa_v){
				new_mat[fa_u].push_back(fa_v+scnt);
			}
		}
		printf("%d\n", scnt - MaxMatch());
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值