题意:
思路:
0.【问题分析】
枚举答案转化为判定性问题,然后最小路径覆盖,可以转化成二分图最大匹配,从而用最大流解决。
【建模方法】
枚举答案A,在图中建立节点1..A。如果对于i<j有i+j为一个完全平方数,连接一条有向边(i,j)。该图是有向无环图,求最小路径覆盖。如果刚好满足最小路径覆盖数等于N,那么A是一个可行解,在所有可行
解中找到最大的A,即为最优解。
具体方法可以顺序枚举A的值,当最小路径覆盖数刚好大于N时终止,A-1就是最优解。
【建模分析】
由于是顺序放球,每根柱子上的球满足这样的特征,即下面的球编号小于上面球的编号。抽象成图论,把每个球看作一个顶点,就是编号较小的顶点向编号较大的顶点连接边,条件是两个球可以相邻,即
编号之和为完全平方数。每根柱子看做一条路径,N根柱子要覆盖掉所有点,一个解就是一个路径覆盖。
最小路径覆盖数随球的数量递增不递减,满足单调性,所以可以枚举答案(或二分答案),对于特定的答案求出最小路径覆盖数,一个可行解就是最小路径覆盖数等于N的答案,求出最大的可行解就是最
优解。本问题更适合枚举答案而不是二分答案,因为如果顺序枚举答案,每次只需要在残量网络上增加新的节点和边,再增广一次即可。如果二分答案,就需要每次重新建图,大大增加了时间复杂度。
输出方案时候不需要重新跑一遍,虽然最后的残余网络比答案多两个点和一些边,但合法那部分的残余网络还是一样的
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef unsigned int uint; 5 typedef unsigned long long ull; 6 typedef long double ld; 7 typedef pair<int,int> PII; 8 typedef pair<ll,ll> Pll; 9 typedef vector<int> VI; 10 typedef vector<PII> VII; 11 typedef pair<ll,ll>P; 12 #define N 100010 13 #define M 3000000 14 #define INF 1e9 15 #define fi first 16 #define se second 17 #define MP make_pair 18 #define pb push_back 19 #define pi acos(-1) 20 #define mem(a,b) memset(a,b,sizeof(a)) 21 #define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++) 22 #define per(i,a,b) for(int i=(int)a;i>=(int)b;i--) 23 #define lowbit(x) x&(-x) 24 #define Rand (rand()*(1<<16)+rand()) 25 #define id(x) ((x)<=B?(x):m-n/(x)+1) 26 #define ls p<<1 27 #define rs p<<1|1 28 29 const ll MOD=1e9+7,inv2=(MOD+1)/2; 30 double eps=1e-6; 31 int dx[4]={-1,1,0,0}; 32 int dy[4]={0,0,-1,1}; 33 34 int head[N],vet[M],len[M],nxt[M],dis[N],p[N],vis[N],tot,S,T,s; 35 36 int read() 37 { 38 int v=0,f=1; 39 char c=getchar(); 40 while(c<48||57<c) {if(c=='-') f=-1; c=getchar();} 41 while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar(); 42 return v*f; 43 } 44 45 void add(int a,int b,int c) 46 { 47 nxt[++tot]=head[a]; 48 vet[tot]=b; 49 len[tot]=c; 50 head[a]=tot; 51 52 nxt[++tot]=head[b]; 53 vet[tot]=a; 54 len[tot]=0; 55 head[b]=tot; 56 } 57 58 bool bfs() 59 { 60 queue<int>q; 61 //rep(i,1,s) dis[i]=-1; 62 rep(i,1,s) dis[i]=dis[i+5000]=-1; 63 dis[T]=-1; 64 q.push(S),dis[S]=0; 65 while(!q.empty()) 66 { 67 int u=q.front(); 68 q.pop(); 69 int e=head[u]; 70 while(e) 71 { 72 int v=vet[e]; 73 if(len[e]&&dis[v]==-1) 74 { 75 dis[v]=dis[u]+1; 76 q.push(v); 77 } 78 e=nxt[e]; 79 } 80 } 81 return dis[T]!=-1; 82 } 83 84 int dfs(int u,int aug) 85 { 86 if(u==T) return aug; 87 int e=head[u],val=0,flow=0; 88 while(e) 89 { 90 int v=vet[e]; 91 if(len[e]&&dis[v]==dis[u]+1) 92 { 93 int t=dfs(v,min(len[e],aug)); 94 if(!t) 95 { 96 e=nxt[e]; 97 continue; 98 } 99 flow+=t; 100 aug-=t; 101 len[e]-=t; 102 len[e^1]+=t; 103 if(!aug) break; 104 } 105 e=nxt[e]; 106 } 107 if(!flow) dis[u]=-1; 108 return flow; 109 } 110 111 int maxflow() 112 { 113 int res=0; 114 while(bfs()) res+=dfs(S,INF); 115 return res; 116 } 117 118 int main() 119 { 120 int n=read(); 121 S=0; T=10000; 122 rep(i,0,T) head[i]=0; 123 tot=1; 124 s=0; 125 int sum=0; 126 while(1) 127 { 128 s++; 129 rep(i,1,s-1) 130 if(sqrt(s+i)==(int)sqrt(s+i)) add(i,s+5000,1); 131 add(S,s,1); 132 add(s+5000,T,1); 133 sum+=maxflow(); 134 int t=s-sum; 135 if(t>n) break; 136 } 137 printf("%d ",s-1); 138 rep(i,1,s-1) 139 { 140 int e=head[i]; 141 while(e) 142 { 143 int v=vet[e]; 144 if(!len[e]){p[i]=v-5000; break;} 145 e=nxt[e]; 146 } 147 } 148 rep(i,1,s-1) 149 { 150 if(vis[i]) continue; 151 int u=i; 152 while(u!=-5000) 153 { 154 vis[u]=1; 155 printf("%d ",u); 156 u=p[u]; 157 } 158 printf(" "); 159 } 160 return 0; 161 }