最長不下降子串行問題
分成三小問解決。
第一小問,求\(lis\),因為\(n<=500\),直接\(o(n^2)\)暴力求解即可。
第二三小問,建立模型用網路流求解。
對於第二小問
\((1)\)首先,因為每個點只能使用一次,考慮拆點,把每乙個點拆成\(i,n+i\)兩個點,從\(i\)連向\(n+i\)一條長度為\(1\)的有向邊。
\((2)\)其次,因為流向是從s經集合e到t,其中任意集合e中元素\(i\)需要滿足的條件是\(i\)位於lis上,故:
①出邊從\(lis[i]=k\)的點流向t
②所有的能構成e的邊都需要加入,也就是任意\(i,j\)滿足\(i都從\(i\)到\(j\)連邊。
跑一遍最大流即可。
第三小問唯一的不同就是\(s\)流向\(1\),\(1\)流向\(1+n\),\(n\)流向\(n+n\),\(n+n\)流向\(t\)四條路長度變成\(inf\)而已,改後再跑一遍最大流即可。
#include#includeint lis[1020],a[1020],len;//lis
int s,t,inf=0x3fffffff;//ek
struct edgeedge[50020];
int head[1020],cnt=2,vis[1020];
void addedge(int begin,int end,int length)
struct prepre[1020];
int bfs(),headq=0,tail=0,i;
queue[tail++]=s;
vis[s]=1;
while(headqedge[en].length)min=edge[en].length;
} for(i=t;i!=s;i=pre[i].pre)
ans+=min;
} return ans;
}int main()
//lis n<=500 o(n2)
for(i=1;i<=n;i++)
for(j=1;j=a[j]&&lis[i]len)len=lis[i];
printf("%d\n",len);
//ek1 建圖求最大流
for(i=1;i<=n;i++)
if(lis[i]==len)
} for(i=1;i<=n;i++)
} }printf("%d\n",ek());
//ek2
memset(pre,0,sizeof(pre));
memset(edge,0,sizeof(edge));
memset(head,0,sizeof(head));
cnt=2;
for(i=1;i<=n;i++)
if(lis[i]==len)
} for(i=1;i<=n;i++)
} }addedge(1,1+n,inf); addedge(1+n,1,0);
addedge(s,1,inf); addedge(1,s,0);
if(lis[n]==len)
printf("%d\n",ek());
return 0;
}
P2766 最長不下降子串行問題
話不多說,直接上思路。其實這就是一道dp動態規劃的經典問題,首先鏈上題目描述 問題描述 設有整數序列b1,b2,b3,bm,若存在 i1 i2 i3 in,且 bi1 bi2 bi3 bin,則稱b1,b2,b3,bm中有長度為n的不下降序列bi1,bi2,bi3,bin。求序列中最大不下降子串行長...
P2766 最長不下降子串行問題
問題描述 給定正整數序列x1,xn 1 計算其最長不下降子串行的長度s。2 計算從給定的序列中最多可取出多少個長度為s的不下降子串行。3 如果允許在取出的序列中多次使用x1和xn,則從給定序列中最多可取出多少個長度為s的不下降子串行。程式設計任務 設計有效演算法完成 1 2 3 提出的計算任務。輸入...
P2766 最長不下降子串行問題
通俗的,對於每個數只能取一次和取無限次,將點拆開加入邊約束 因為讓求最長上公升子串行的個數,所以當乙個數字被選擇時,它必須是最長上公升子串行的一部分 我們求出最長上公升子串行的 dp 陣列,當 x 可以連邊 y 當且僅當 y 在 dp 中可以從 x 轉移過來 這樣問題就顯然了,我們只需要求解 dag...