★★★☆ 輸入檔案:alis.in
輸出檔案:alis.out
簡單對比
時間限制:1 s 記憶體限制:128 mb
«問題描述:
給定正整數序列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
43 6 2 5
alis.out22
3【問題分析】
第一問是lis,動態規劃求解,第二問和第三問用網路最大流解決。
【建模方法】
首先動態規劃求出f[i],表示以第i位為開頭的最長上公升序列的長度,求出最長上公升序列長度k。
1、把序列每位i拆成兩個點和,從到連線一條容量為1的有向邊。
2、建立附加源s和匯t,如果序列第i位有f[i]=k,從s到連線一條容量為1的有向邊。
3、如果f[i]=1,從到t連線一條容量為1的有向邊。
4、如果j>i且a[i] < a[j]且f[j]+1=f[i],從到連線一條容量為1的有向邊。
求網路最大流,就是第二問的結果。把邊(<1.a>,<1.b>)(,)(s,<1.a>)(,t)這四條邊的容量修改為無窮大,再求一次網路最大流,就是第三問結果。
【建模分析】
上述建模方法是應用了一種分層圖的思想,把圖每個頂點i按照f[i]的不同分為了若干層,這樣圖中從s出發到t的任何一條路徑都是乙個滿足條件的最長上公升子串行。由於序列中每個點要不可重複地取出,需要把每個點拆分成兩個點。單位網路的最大流就是增廣路的條數,所以最大流量就是第二問結果。第三問特殊地要求x1和xn可以重複使用,只需取消這兩個點相關邊的流量限制,求網路最大流即可。
ps:任務3若能取出無限多的序列,則輸出任務2的答案
//資料略坑
#include
#include
#include
#define
setfile
(name
)freopen
(#name".in","r",stdin);freopen(#name".out","w",stdout);
using
namespace
std;
const
intn
=1005
;const
intinf
=1e9
;struct
edgee[
n*n*
2];inttot=1
,head[n
];intn,
s,t,
k,ans,a[
n],f[
n],dis[n],
q[n*
n*2];
inline
intread
()while(ch
>=
'0'&&
ch<=
'9')
returnx*
f;}inline
void
add(
intx
,inty,
intz
)inline
bool
bfs()}}
return0;
}int
dfs(
intx
,intf)
}if(!used
)dis[x
]=-1
;return
used;}
inline
intdinic
()inline
void
dp()}}
k=*max_element(f
+1,f
+n+1
);}void
init
()void()}
}}inline
void
work
()ans
=dinic
();printf
("%d\n"
,ans
);();
for(
inti=1
;i<=n;
i++)
intlastans
=ans
;ans
=dinic
();if
(ans
>
inf)
printf
("%d\n"
,lastans
);else
printf
("%d\n"
,ans);}
intmain
()
網路流 24 題 最長遞增子串行
1 dp求一遍 2 所有點拆成入點和出點,對於沒個f i 1的1點連源點,每個f i ans1的點連匯點,每個點的入點和出點再連一條邊,所有容量為1,求一遍最大流。2 1和n可以用多次,所以對於點1和點n,入點和出的連邊的容量變為inf,如果需要連源點或匯點那麼容量也變為n,其餘容量為1,求一遍最大...
網路流24題 最長遞增子串行
給定正整數序列x1,xn。1 計算其最長遞增子串行的長度s。2 計算從給定的序列中最多可取出多少個長度為s的遞增子串行。3 如果允許在取出的序列中多次使用x1和xn,則從給定序列中最多可取出多少個長度為s的遞增子串行。設計有效演算法完成 1 2 3 提出的計算任務 第1 行有1個正整數n n 500...
網路流24題6 最長遞增子串行
給定正整數序列x1,xn 1 計算其最長遞增子串行的長度s。2 計算從給定的序列中最多可取出多少個長度為s的遞增子串行。3 如果允許在取出的序列中多次使用x1和xn,則從給定序列中最多可取出多少個長度為s的遞增子串行。設計有效演算法完成 1 2 3 提出的計算任務。第一問秒掉 第二問比較難想到,每個...