腦抽寫了個費用流$T$飛了,看了題解才明白是怎麼跑最大流的
這道題有一個貪心,如果小於它的數沒有能和它之和是完全平方數的,那麼它一定要新建一個柱子
證明可以看poorpool神犇的這篇部落格
由於每個點只能用一次,所以每個點$x$拆成$2$個點$x1$和$x2$,$x1$和源點相連,$x2$和匯點相連,流量均為$1$
而如果兩個數$x,y$能構成完全平方數,那麼$x1$連線$y2$
我們從小到大遍歷每個數$x$,然後在圖內加入$x2$,如果產生了一條新流,說明$x$能找到一個$y(y<x)$,$x+y$是完全平方數
否則,我們新加入一個柱子
然後不論能否產生新流,把$x1$加入到圖中
驗證是否產生新流可以用$Dinic$最大流實現
為什麼要這麼做呢?
我們是動態往圖裡加的點,每次加完點以後,如果情況合法,會產生一條新流。
如果不這麼做,我們每次要重新建邊,大大拉高的時間複雜度
如何記錄方案呢?
一個柱子裡的點會形成一條鏈(即使在網路流圖內它看起來不是一條鏈)。
可以向並查集一樣,開一個陣列,在$Dinic$裡記錄每個點的流量流向哪個位置就行了
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define N1 8010 6 #define M1 40010 7 #define ll long long 8 #define dd double 9 #define inf 0x3f3f3f3f 10 using namespace std; 11 12 int gint() 13 { 14 int ret=0,fh=1;char c=getchar(); 15 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 16 while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} 17 return ret*fh; 18 } 19 struct Edge{ 20 int head[N1],to[M1<<1],nxt[M1<<1],flow[M1<<1],cte; 21 void ae(int u,int v,int F) 22 { 23 cte++; to[cte]=v; flow[cte]=F; 24 nxt[cte]=head[u]; head[u]=cte; 25 } 26 }e,E; 27 int n,m,K,S,T,F,mx; 28 int que[M1],hd,tl,dep[N1],cur[N1],pre[N1]; 29 int bfs() 30 { 31 int x,j,v; 32 memset(dep,-1,sizeof(dep)); memcpy(cur,e.head,sizeof(cur)); 33 hd=1,tl=0; que[++tl]=S; dep[S]=0; 34 while(hd<=tl) 35 { 36 x=que[hd++]; 37 for(j=e.head[x];j;j=e.nxt[j]) 38 { 39 v=e.to[j]; 40 if( e.flow[j]>0 && dep[v]==-1 ) 41 dep[v]=dep[x]+1, que[++tl]=v; 42 } 43 } 44 return dep[T]!=-1; 45 } 46 int dfs(int x,int limit) 47 { 48 int j,v,flow,ans=0; if(x==T||!limit) return limit; 49 for(j=cur[x];j;j=e.nxt[j]) 50 { 51 cur[x]=j; v=e.to[j]; 52 if( dep[v]==dep[x]+1 && (flow=dfs(v,min(e.flow[j],limit))) ) 53 { 54 limit-=flow; ans+=flow; 55 e.flow[j]-=flow; e.flow[j^1]+=flow; 56 if(v>n*n&&v<=2*n*n) pre[x]=v-n*n; 57 if(!limit) break; 58 } 59 } 60 return ans; 61 } 62 63 int stk[N1],tp; 64 65 int de; 66 int Dinic() 67 { 68 int mxflow=0; 69 while(bfs()) 70 mxflow+=dfs(S,inf); 71 return mxflow; 72 } 73 void solve() 74 { 75 int i,j,k,sq,num=0,ans,x; 76 S=0; T=2*mx+1; e.cte=1; 77 for(i=1;i<=mx;i++) 78 { 79 //e.ae(i,i+mx,1); e.ae(i+mx,i,0); 80 for(j=n;j>1;j--) 81 { 82 k=j*j-i; 83 if(k>0&&k<i) 84 e.ae(k,i+mx,1),e.ae(i+mx,k,0); 85 } 86 e.ae(i+mx,T,1); e.ae(T,i+mx,0); 87 if(Dinic()<=0){ 88 if(num+1>n){ ans=i-1; break;} 89 stk[++tp]=i; num++; 90 } 91 e.ae(S,i,1); e.ae(i,S,0); 92 } 93 printf("%d\n",ans); 94 for(i=1;i<=n;i++) 95 { 96 x=stk[i]; 97 while(x) printf("%d ",x), x=pre[x]; 98 puts(""); 99 } 100 } 101 102 int main() 103 { 104 scanf("%d",&n); mx=n*n; 105 solve(); 106 return 0; 107 }