洛谷 P2765 魔術球問題 (網路流24題)
阿新 • • 發佈:2018-12-12
題目:魔術球問題
思路: 聽說這題答案的範圍很小。 聽說從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;
}