[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那里拿个数组记录一下就好了。

 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 }
View Code

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]) )好写多了= =

   诶这题和题目有什么关系吗= =

你可能感兴趣的:([bzoj3997] [TJOI2015]组合数学)