[网络流24题]魔术球问题 贪心||枚举答案+最小路径覆盖
2016-03-09 21:09
465 查看
问题描述:
假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为 1,2,3,4……的球。(1)每次只能在某根柱子的最上面放球。
(2)在同一根柱子中,任何2个相邻球的编号之和为完全平方数。
试设计一个算法,计算出在n根柱子上最多能放多少个球。例如,在4 根柱子上最多可
放11个球。
´编程任务:
对于给定的n,计算在 n根柱子上最多能放多少个球。´数据输入:
文件第1 行有 1个正整数n,表示柱子数。´结果输出:
文件的第一行是球数。数据规模
n<=60 保证答案小于1600输入文件示例
4
输出文件示例
11 1 8 2 7 9 3 6 10 4 5 11
贪心好简单…
尽量选少的柱子,实在不行了再放新柱子上…
网络流:
枚举答案A,在图中建立节点1..A。如果对于i<j有i+j为一个完全平方数,连接一条有向边(i,j)。该图是有向无环图,求最小路径覆盖。如果刚好满足最小路径覆盖数等于N,那么A是一个可行解,在所有可行解中找到最大的A,即为最优解。
具体方法可以顺序枚举A的值,当最小路径覆盖数刚好大于N时终止,A-1就是最优解。
简直神,然而为什么不贪心呢……
网络流:
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> #include<queue> using namespace std; const int INF = 1000000010; const int SZ = 1000010; int head[SZ],nxt[SZ],tot = 1,n; struct edge{ int t,d; }l[SZ]; void build(int f,int t,int d) { l[++ tot].t = t; l[tot].d = d; nxt[tot] = head[f]; head[f] = tot; } void insert(int f,int t,int d) { build(f,t,d); build(t,f,0); } int deep[SZ]; queue<int> q; bool bfs(int s,int e) { memset(deep,0,sizeof(deep)); deep[s] = 1; while(q.size()) q.pop(); q.push(s); while(q.size()) { int u = q.front(); q.pop(); for(int i = head[u];i;i = nxt[i]) { int v = l[i].t; if(!deep[v] && l[i].d) { deep[v] = deep[u] + 1; q.push(v); if(v == e) return true; } } } return false; } int dfs(int u,int flow,int e) { if(u == e || flow == 0) return flow; int rest = flow; for(int i = head[u];i;i = nxt[i]) { int v = l[i].t; if(deep[v] == deep[u] + 1 && l[i].d) { int f = dfs(v,min(rest,l[i].d),e); if(f > 0) { l[i].d -= f; l[i ^ 1].d += f; rest -= f; if(rest == 0) break; } else deep[v] = 0; } } return flow - rest; } int dinic(int s,int e) { int ans = 0; while(bfs(s,e)) ans += dfs(s,INF,e); return ans; } void init() { tot = 1; memset(head,0,sizeof(head)); } const int CD = 5000; int s = 50000,e = 50001; int check(int now,int &ans) { for(int i = 1;i < now;i ++) { int x = i + now; int y = sqrt(x); if(x == y * y) insert(i,CD + now,1); } insert(s,now,1); insert(now + CD,e,1); ans += dinic(s,e); return now - ans; } bool vis[SZ]; int ans = 0; bool dfs(int u) { if(u > CD) u -= CD; // if(vis[u]) return true; // vis[u] = 1; printf("%d ",u); bool flag = 0; for(int i = head[u];i;i = nxt[i]) { int v = l[i].t; if(!vis[v] && v > CD && v <= CD * 2) { flag = 1; vis[v] = 1; if(dfs(v)) return true; } } if(flag) return false; return true; } void final(int now) { init(); for(int i = 1;i <= now;i ++) for(int j = i + 1;j <= now;j ++) { int x = i + j; int y = sqrt(x); if(x == y * y) insert(i,j + CD,1); } for(int i = 1;i <= now;i ++) insert(s,i,1); for(int i = 1;i <= now;i ++) insert(CD + i,e,1); dinic(s,e); } int main() { scanf("%d",&n); int maxflow = 0; for(ans = 1;;ans ++) if(check(ans,maxflow) > n) break; ans --; final(ans); printf("%d\n",ans); for(int i = 1;i <= ans;i ++) if(!vis[i + CD] && dfs(i)) puts(""); return 0; }
贪心:
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> #include<queue> #include<vector> using namespace std; const int SZ = 100010; vector<int> g[SZ]; bool check(int x) { int y = sqrt(x); return y * y == x; } int main() { int n; scanf("%d",&n); int now = 1,num = 2; g[1].push_back(1); while(233) { bool flag = 0; if(g[now].size() == 0) g[now].push_back(num ++); for(int i = 1;i <= now;i ++) { if((check(g[i].back() + num))) { flag = 1; g[i].push_back(num ++); break; } } if(!flag) { if(now < n) now ++; else break; } } printf("%d\n",num - 1); for(int i = 1;i <= n;i ++,puts("")) for(int j = 0;j < g[i].size();j ++) printf("%d ",g[i][j]); return 0; }
相关文章推荐
- MES案例研究2 – OPC网络阻塞
- HDU 1853Cyclic Tour(网络流之最小费用流)
- HttpServletRequest对象(一)
- 嵌入式系统网络通信
- Java网络编程——URL
- HttpServletRequest对象方法的用法
- 从输入一个URL到页面呈现,网络上都发生了什么?
- Unity3D 集成 Face++ FacePlusPlus httpClient http协议 byte数组转string
- TCP三次握手和释放
- 解决Win10创建wifi热点时出现无法启动承载网络的情况
- WebSocket 实战
- LSTM长短期记忆网络
- okhttp的简单介绍(二)之简单封装
- Java网络编程——InetAddress
- 常用网络管理操作
- Okhttp的简单介绍和使用(一)
- 【Http专题】Https
- HTTPS证书生成方法,也适用于APP
- 使用open vswitch构建虚拟网络
- http与websocket两种协议下的跨域基于ASP.NET MVC--竹子整理