洛谷 P2765 魔术球问题 (网络流24题)

版权声明:欢迎转载欢迎评论! https://blog.csdn.net/rabbit_ZAR/article/details/82860133

题目:魔术球问题

思路:
听说这题答案的范围很小。
听说从1开始枚举答案大小不会超时。
然后我就枚举答案了。
假设答案为m,就对于m个数,每个数暴力的寻找可以可以放在它下面的数再建边。
由于只有可能上面的点指向下面的点,所以这张图不存在环,可见是一张二分图。
然后从m开始跑一遍匈牙利算法看看能否求出增广路,如果不能,则说明无法对m进行匹配,则需要再加一根柱子放m。
当柱子的数量大于n时,就说明m-1即为答案。
然后顺着match数组找路径就好了。

代码:

#include<bits/stdc++.h>
using namespace std;

#define maxn 55
#define maxm 2000
#define m maxm
#define read(x) scanf("%d",&x)

int n;
bool isq[maxm*maxm+5];
vector<int> a[maxm+5];

bool use[maxm+5];
int match[maxm+5];

void init() {
	for(int i=1;i<=m;i++) {
		isq[i*i]=true;
	}
}

void add(int x) {
	for(int i=1;i<x;i++) {
		if(isq[i+x]) a[x].push_back(i);
	}
}

bool dfs(int x) {
	if(use[x]) return false;
	use[x]=true;
	for(int i=0;i<a[x].size();i++) {
		int y=a[x][i];
		if(!match[y]||dfs(match[y])) {
			match[y]=x;
			return true;
		}
	}
	return false;
}

void print(int x) {
	while(x) {
		printf("%d ",x);
		use[x]=true;
		x=match[x];
	}
	printf("\n");
}

int main() {
	read(n);
	init();
	int nxt=0;
	for(int i=0;i<=n;i++) {
		for(int j=nxt+1;j<=m;j++) {
			add(j);
			if(!dfs(j)) {
				nxt=j;
				break;
			}
			memset(use,0,sizeof(use));
		}
	}
	nxt--;
	printf("%d\n",nxt);
	for(int i=1;i<=nxt;i++) {
		if(use[i]) continue;
		print(i);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/rabbit_ZAR/article/details/82860133