【题解】10.31模拟赛T2:蓝精灵的请求

本文介绍了一种基于图算法的比赛解决方案,通过使用广度优先搜索(BFS)和深度优先搜索(DFS)来处理复杂的图问题。文章详细描述了如何通过构建点集并利用暴力DFS求解最优解的过程。

在这里插入图片描述
在这里插入图片描述
我的做法是乱搞,跟std完全不一样
首先如果两个点之间没有边,那么这两个点肯定属于不同的点集
可以bfsbfsbfs处理肯定属于同一点集的点
然后处理出一些点集,整体思想点集之间如果可以合并成同一个点集就连一条边
跑暴力dfsdfsdfs求得答案

Code:

#include <bits/stdc++.h>
#define maxn 710
using namespace std;
int n, m, flag[maxn][maxn], Flag[maxn][maxn], num, color[maxn], type[maxn];
int cnt[maxn][2], a[maxn][2][maxn], can[maxn][2][maxn][2], ans;
queue <int> q;

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

bool check(int x, int p, int y, int q){
	for (int i = 1; i <= cnt[x][p]; ++i)
		for (int j = 1; j <= cnt[y][q]; ++j)
			if (Flag[a[x][p][i]][a[y][q][j]]) return 0;
	return 1;
}

void dfs(int t, int sum1, int sum2){
	if (t > num) ans = min(ans, sum1 * (sum1 - 1) / 2 + sum2 * (sum2 - 1) / 2); else{
		if (can[t - 1][0][t][0] && can[t - 1][1][t][1]) dfs(t + 1, sum1 + cnt[t][0], sum2 + cnt[t][1]);
		if (can[t - 1][0][t][1] && can[t - 1][1][t][0]) dfs(t + 1, sum2 + cnt[t][0], sum1 + cnt[t][1]);
	}
}

int main(){
	freopen("request.in", "r", stdin);
	freopen("request.out", "w", stdout);
	n = read(), m = read();
	for (int i = 1; i <= m; ++i){
		int x = read(), y = read();
		flag[x][y] = flag[y][x] = 1;
	}
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			if (i != j && !flag[i][j]) Flag[i][j] = Flag[j][i] = 1;
	for (int i = 1; i <= n; ++i)
		if (!color[i]){
			color[i] = ++num, type[i] = 1;
			q.push(i);
			while (!q.empty()){
				int u = q.front(); q.pop();
				for (int j = 1; j <= n; ++j)
					if (Flag[u][j] && !color[j]){
						color[j] = num, type[j] = type[u] ^ 1;
						q.push(j);
					}
			}
		}
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			if (i != j && color[i] == color[j] && type[i] == type[j] && Flag[i][j]) return puts("-1"), 0;
	for (int i = 1; i <= num; ++i){
		for (int j = 1; j <= n; ++j)
			if (color[j] == i && type[j]) a[i][1][++cnt[i][1]] = j; else
			if (color[j] == i && !type[j]) a[i][0][++cnt[i][0]] = j;
	}
	for (int i = 1; i < num; ++i)
		for (int j = 0; j <= 1; ++j)
			for (int k = 0; k <= 1; ++k)
				if (check(i, j, i + 1, k)) can[i][j][i + 1][k] = 1;
	ans = 1e9;
	dfs(2, cnt[1][0], cnt[1][1]);
	printf("%d\n", ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值