1. 程式人生 > >[網絡流24題] 最長遞增子序列

[網絡流24題] 最長遞增子序列

sin 示例 d+ 個數 分享圖片 技術 dinic 自己 長度

[網絡流24題] 最長遞增子序列

«問題描述:
給定正整數序列x1,..., xn。
(1)計算其最長遞增子序列的長度s。
(2)計算從給定的序列中最多可取出多少個長度為s的遞增子序列。
(3)如果允許在取出的序列中多次使用x1和xn,則從給定序列中最多可取出多少個長
度為s的遞增子序列。

註意:這裏的最長遞增子序列即最長不下降子序列!!!
«編程任務:
設計有效算法完成(1)(2)(3)提出的計算任務。
«數據輸入:
由文件alis.in提供輸入數據。文件第1 行有1個正整數n(n<=500),表示給定序列的長度。接
下來的1 行有n個正整數x1,..., xn。

«結果輸出:
程序運行結束時,將任務(1)(2)(3)的解答輸出到文件alis.out中。第1 行是最長
遞增子序列的長度s。第2行是可取出的長度為s 的遞增子序列個數。第3行是允許在取出
的序列中多次使用x1和xn時可取出的長度為s 的遞增子序列個數。
輸入文件示例 輸出文件示例
alis.in
4

3 6 2 5

alis.out

2
2
3

題目描述的不是很清楚,不是遞增,是不下降,另外無限用事實上指的是1和n可以被用於多個不下降序列中,可以重復使用,而其他點只可以用一次。

對於第一問,隨便求一下就行...

對於後兩問,我們想到網絡流的方法(畢竟網絡流24題),如何限制一個點的經過次數呢?我們可以把它拆成兩個點,在兩個點之間連一條權值為x的邊,表示這個點最多經過x次。那如何建圖呢,對於兩個位置i,j,如果a[i]<=a[j]並且i<j並且g[i]+1=g[j],那麽我們就可以在他們之間連一條邊,想一下也很簡單。那麽與源點(S)和匯點(T)如何連邊呢?

對於第二問的情況,連1就行了,因為最多用一次。

對於第三問,非無限取的點和第二問一樣,對於無限取的點,他與S相連的權值至少應該為他可能作為起點出現的次數a,與T相連的權值至少應該為他可能作為終點出現的次數b。對於只與S或者只與T相連的點,這種點的存在說明了最長不下降子序列長度不為1,我們邊的權值可以取任意大於等於a或者b數字,因為其他的點會對他做出限制,他取大一點也沒關系,反正也流不了那麽多,但對於s與t均連在一個點上的情況,說明最長不下降序列長度為1,這時候a,b中比較小的那一個(其實這種情況全是1),就必須取他本身,也就是1,才能“限制”住,不然的話他的流量就變成inf了。而1這個點又比較特殊,如果他可以作為終點出現,那麽說明最長不下降序列長度為1,也就一定可以作為起點出現,那麽1和t的連邊權值一定是1,n點同理,與s連邊權值一定是1,。

語文比較差,,,可能講不清楚。也可能講的就是錯的qwq,因為我yy了一下午也就很牽強的說服了自己。。。

技術分享圖片
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int inf=1e6;//隨便開...
  4 int n,a[inf],f[inf],g[inf],top;
  5 int tot,fi[inf],to[inf],next[inf],cost[inf],rev[inf];
  6 int ans,que[inf],head,tail,dep[inf],cur[inf]; 
  7 void slove1(){
  8     for(int i=1;i<=n;i++){
  9         if(a[i]>=f[top])f[++top]=a[i],g[i]=top;
 10         else {
 11             int l=1,r=top;
 12             while(l!=r){
 13                 int mid=(l+r)>>1;
 14                 if(f[mid]<=a[i])l=mid+1;
 15                 else r=mid;
 16             }
 17             f[l]=a[i];
 18             g[i]=l;
 19         }
 20     }
 21     printf("%d\n",top);
 22 }
 23 void edge_add(int x,int y,int z){
 24     to[++tot]=y;next[tot]=fi[x];
 25     fi[x]=tot;cost[tot]=z;rev[tot]=tot+1;
 26     to[++tot]=x;next[tot]=fi[y];
 27     fi[y]=tot;cost[tot]=0;rev[tot]=tot-1;
 28 }
 29 bool bfs(){
 30     for(int i=1;i<=n*2+2;i++)cur[i]=fi[i],dep[i]=-1;
 31     dep[1]=0;
 32     head=1;tail=0;
 33     que[++tail]=1;
 34     while(head<=tail){
 35         int u=que[head++];
 36         for(int i=fi[u];i;i=next[i])
 37             if(cost[i]&&dep[to[i]]==-1)
 38                 dep[to[i]]=dep[u]+1,
 39                 que[++tail]=to[i];
 40     }
 41     return dep[n*2+2]!=-1;
 42 }
 43 int dfs(int x,int f){
 44     if(x==n*2+2)return f;
 45     for(int i=cur[x];i;i=next[i]){
 46         cur[x]=i;
 47         if(cost[i]&&dep[to[i]]==dep[x]+1){
 48             int g=dfs(to[i],min(f,cost[i]));
 49             if(g){
 50                 cost[i]-=g;
 51                 cost[rev[i]]+=g;
 52                 return g;
 53             }
 54         }
 55     }
 56     return 0;
 57 }
 58 void dinic(){
 59     ans=0;
 60     int f;
 61     while(bfs())
 62         while(f=dfs(1,0x3fffffff))ans+=f;
 63     printf("%d\n",ans);
 64 }
 65 int main()
 66 {
 67     freopen("alis.in","r",stdin);
 68     freopen("alis.out","w",stdout);
 69 //    freopen("1.txt","r",stdin);
 70     scanf("%d",&n);
 71     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
 72     slove1();
 73     for(int i=1;i<=n;i++){
 74         edge_add(i<<1,i<<1|1,1);
 75         if(g[i]==1)edge_add(1,i<<1,1);
 76         if(g[i]==top)edge_add(i<<1|1,n*2+2,1);
 77     }
 78     for(int i=1;i<n;i++)
 79         for(int j=i+1;j<=n;j++)
 80             if(a[i]<=a[j]&&g[i]+1==g[j])
 81                 edge_add(i<<1|1,j<<1,1);
 82     dinic();
 83     tot=0;
 84     memset(fi,0,sizeof(fi));
 85     memset(to,0,sizeof(to));
 86     memset(next,0,sizeof(next));
 87     memset(rev,0,sizeof(rev));
 88     memset(cost,0,sizeof(cost));
 89     for(int i=1;i<=n;i++){
 90         edge_add(i<<1,i<<1|1,1);
 91         if(g[i]==1)edge_add(1,i<<1,1);
 92         if(g[i]==top)edge_add(i<<1|1,n*2+2,1);
 93     }
 94     for(int i=1;i<n;i++)
 95         for(int j=i+1;j<=n;j++)
 96             if(a[i]<=a[j]&&g[i]+1==g[j])
 97                 edge_add(i<<1|1,j<<1,1);
 98     edge_add(2,3,0x3fffffff);edge_add(n<<1,n<<1|1,0x3fffffff);
 99     if(g[1]==1)edge_add(1,2,0x3fffffff);
100     if(g[n]==top)edge_add(n<<1,n*2+2,0x3fffffff);
101     dinic();
102     return 0;
103 }
View Code

[網絡流24題] 最長遞增子序列