P2765 魔术球问题&&二分图
题意
思路
1
根据此题输入m的范围,可以知道此题的答案上限约为5000
考虑逆向二分求解(实际上可以直接枚举)
2
此题可以抽象成在图上求最少链的个数
我们把所有数向比他大的、与他的和为平方数的数建边
可以看出是二分图最大匹配问题
结合图更清晰:
此时图上最少链的个数为
这三条链分别为:
1 3 6
4 5
2
可以看作从
- 左边的 1 连接了右边的 3,这条链上有
。3已经被加到一条链中,标记一下,再遍历到 3 时直接跳过
左边的 3 又连接到了右边的 6,这条链就变成了 标记 6 - 左边的 2 没有连接右边的点,这条链上只有
- 遍历到 3,3 已经被标记,continue
- 4 连接了 5,标记 5,此时这条链变为
- 5 被标记,continue
- 6 被标记,结束。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn=5005; int m; vector<int>g[maxn*2]; int result[maxn*2]; int mm[maxn*2]; bool vis[maxn*2]; bool dfs(int p) { for(int j=0;j<g[p].size();j++) { if(!vis[g[p][j]]){ vis[g[p][j]]=true; if(result[g[p][j]]==0||dfs(result[g[p][j]])) { result[g[p][j]]=p; mm[p]=g[p][j]; return true; } } } return false; } bool is_sqre(int p) { int t = sqrt(p); if(t * t == p){ return true; } return false; } bool check(int n) { memset(mm,0,sizeof(mm)); int ans=0; for(int i=1;i<=n;i++) g[i].clear(); memset(result,0,sizeof(result)); for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { if(is_sqre(i+j)) g[i].push_back(j); } } for(int i=1;i<=n;i++) { if(dfs(i)) ans++; memset(vis,false,sizeof(vis)); } if(n-ans>m) return false;//需要更多的柱子 else return true; } int main() { cin>>m; int l=1,r=5000; while(l<r){ int mid=(l+r)>>1; if(check(mid)) l=mid+1; else r=mid; } cout<<l-1<<endl; for(int j=1;j<=l-1;j++) { if(!vis[j]) { for(int i=j;i;i=mm[i]) { cout<<i<<" "; vis[i]=true; } cout<<endl; } } return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战