[bzoj3997] [TJOI2015]组合数学
题目要求最小路径覆盖。。DAG的最小路径覆盖=最长反链=n-对应二分图最大匹配数。。
反链:一些点的集合,使得任意两点之间不存在路径。最长反链:反链里面节点数的最大值。
一开始还以为要跑网络流。。。最后根据黄学长的题解可得,这题应该求的是最长反链TAT
因为是只能往下或者往右的网格图,所以反链的点一定是左下-右上的。dp一下就好了。。
f[i][j]表示反链中最右上的节点在第i行第j列时的最长反链。map[i][j]表示第i行第j列的点的权值。
f[i][j]=map[i][j]+max{ f[i-1][j]-map[i-1][j] , f[i-1][k] },(j+1<=k<=n)。k那里拿个数组记录一下就好了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define ll long long 5 using namespace std; 6 const int maxn=1003; 7 int mp[maxn][maxn]; 8 ll f[maxn],ans,mx[maxn]; 9 int i,j,k,n,m; 10 11 int ra;char rx; 12 inline int read(){ 13 rx=getchar(),ra=0; 14 while(rx<'0'||rx>'9')rx=getchar(); 15 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; 16 } 17 inline ll max(ll a,ll b){return a>b?a:b;} 18 int main(){ 19 register int i,j,k; 20 for(int T=read();T;T--){ 21 n=read(),m=read(),ans=0; 22 for(i=1;i<=n;i++)for(j=1;j<=m;j++)mp[i][j]=read(); 23 memset(mx,0,(m+1)<<2); 24 for(i=1;i<=m;i++){ 25 mx[i]=mp[n][i]; 26 if(mx[i]>ans)ans=mx[i]; 27 } 28 for(i=n-1;i;i--) 29 for(f[1]=mp[i][1],j=2,k=1;j<=m;j++,k++){ 30 f[j]=(ll)mp[i][j]+max(mx[k],f[k]-mp[i][k]);//printf(" %d %d %lld\n",i,j,f[j]); 31 if(f[j]>ans)ans=f[j]; 32 if(f[k]>mx[k])mx[k]=f[k]; 33 } 34 printf("%lld\n",ans); 35 } 36 return 0; 37 }
UPD:如果f[i][j]表示反链最右上节点在(i,j)及其左下方(包括左、下)时的最长反链,
那么f[i][j]=max(map[i][j]+f[i-1][j+1] , max(f[i-1][j],f[i][j+1]) )好写多了= =
诶这题和题目有什么关系吗= =