• hdu 2686 费用流 / 双线程DP


    题意:给一个方阵,求从左上角出到右下角(并返回到起点),经过每个点一次不重复,求最大获益(走到某处获得改点数值),下来时每次只能向右或向下,反之向上或向左。

    俩种解法:

    1  费用流法:思路转化:从左上角流出2的流量,(表示走俩条路),归于右下角,可以走就有边(右和下),权为负的费用,源点连起点,汇点连终点,流量为2. 除源汇外所有点一分为2,Y向X对应点有流量1的边,之前边为X到Y的(原图),这样处理解决每个点只最多走一次(除了源汇外)(X部只出,Y部要出必先回到X对应点)。跑最小费用最大流即可。


    2:dp法:(感谢XX大牛的提示)俩个点同时走,走了第K步状态:为x1,y1;x2,y2,  由于(x1+y1=k,x2+y2=k),状态压缩为3维,每个状态表示当前这步俩个点的横左边。

     dp[k][x1][x2]=max(dp[k-1][x1][x2],dp[k-1][x1][x2-1],dp[k-1][x1-1][x2],dp[k-1][x1-1][x2-1])


    方法1:

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<cstring>
    using namespace std;
    const int inf=0x3f3f3f3f;
    int a[50][50];
    int nume=0;int e[50000][4];int head[2000];
    int n;
    void inline  adde(int i,int j,int c,int w)
    {
        e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;
        e[nume][2]=c;e[nume++][3]=w;
        e[nume][0]=i;e[nume][1]=head[j];head[j]=nume;
        e[nume][2]=0;e[nume++][3]=-w;
    }
    int inq[2000];int pre[2000];int prv[2000];
    int d[2000];
    bool spfa(int &sum)
    {
        for(int i=0;i<=2*n*n+2;i++)
              {
                  inq[i]=0;
                  d[i]=inf;
              }
        queue<int>q;
        q.push(2*n*n);
        inq[2*n*n]=1;
        d[2*n*n]=0;
        while(!q.empty())
        {
            int cur=q.front();
            q.pop();
            inq[cur]=0;
            for(int i=head[cur];i!=-1;i=e[i][1])
            {
                int v=e[i][0];
                if(e[i][2]>0&&d[cur]+e[i][3]<d[v])
                {
                    d[v]=d[cur]+e[i][3];
                    pre[v]=i;
                    prv[v]=cur;
                    if(!inq[v])
                    {
                        q.push(v);
                        inq[v]=1;
                    }
                }
            }
        }
        if(d[2*n*n+1]==inf)return 0;
        int cur=2*n*n+1;int minf=inf;
        while(cur!=2*n*n)
        {
            minf=e[pre[cur]][2]<minf?e[pre[cur]][2]:minf;
            cur=prv[cur];
        }
         cur=2*n*n+1;
        while(cur!=2*n*n)
        {
            e[pre[cur]][2]-=minf;
            e[pre[cur]^1][2]+=minf;
            cur=prv[cur];
        }
        sum+=minf*d[2*n*n+1];
        return 1;
    }
    
    int mincost()
    {
        int sum=0;
        while(spfa(sum));
        return sum;
    }
    void init()
    {
        nume=0;
        memset(head,-1,sizeof(head));
    }
    int main()
    {
        while(~scanf("%d",&n))
        {
            init();
            for(int i=0;i<n;i++)
                for(int j=0;j<n;j++)
                 scanf("%d",&a[i][j]);
            for(int i=0;i<n;i++)
                for(int j=0;j<n;j++)
                {
                    if(i+1<n)
                    adde(i*n+j,(i+1)*n+j+n*n,1,-a[i+1][j]);
                    if(j+1<n)
                    adde(i*n+j,i*n+j+1+n*n,1,-a[i][j+1]);
                }
            for(int i=0;i<n*n;i++)
            {
                adde(i+n*n,i,1,0);
            }
             adde(2*n*n,0,2,0);
            adde(2*n*n-1,2*n*n+1,2,0);
            int ans=-mincost();
           ans+=a[0][0];
           ans-=a[n-1][n-1];
            printf("%d
    ",ans);
        }
        return 0;
    }
    


    方法2

    ;

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    int a[50][50];
    int dp[80][50][50];
    int max(int x,int y,int z,int t)
    {
        if(x>=y&&x>=z&&x>=t)return x;
        if(y>=x&&y>=z&&y>=t)return y;
        if(z>=x&&z>=y&&z>=t)return z;
        return t;
    }
    int main()
    {
        int n;
        while(~scanf("%d",&n))
        {
            memset(dp,0,sizeof(dp));
            for(int i=0;i<n;i++)
                for(int j=0;j<n;j++)
                 scanf("%d",&a[i][j]);
               dp[0][0][0]=a[0][0];
               dp[1][0][1]=a[0][1]+a[0][0]+a[1][0];
    
              for(int k=1;k<=2*n-2;k++)
              {
                  for(int x1=0;x1<=k&&x1<n;x1++)
                  {
                      for(int x2=0;x2<=k&&x2<n;x2++)
                      {
                          if(x1!=x2)
                          {
                              if(x1>0&&x2>0)
                            dp[k][x1][x2]=max(dp[k-1][x1][x2],dp[k-1][x1][x2-1],dp[k-1][x1-1][x2],dp[k-1][x1-1][x2-1]);
                            else if(x1==0&&x2>0)
                            {
                                dp[k][x1][x2]=max(dp[k-1][x1][x2],dp[k-1][x1][x2-1],0,0);
                            }
                            else
                            {
                                dp[k][x1][x2]=max(dp[k-1][x1][x2],dp[k-1][x1-1][x2],0,0);
                            }
                            dp[k][x1][x2]+=(a[x1][k-x1]+a[x2][k-x2]);
    
                          }
                      }
                  }
              }
              int ans=dp[2*n-3][n-2][n-1]+a[n-1][n-1];
              cout<<ans<<endl;
        }
        return 0;
    }
    

  • 相关阅读:
    牡牛和牝牛
    卡特兰数 Catalan number
    Codeforces Round #633 (Div. 2)
    Codeforces Round #634 (Div. 3)
    陪审团
    线性DP
    AcWing 274. 移动服务
    Rust打印方法行号
    八.枚举与模式匹配
    七.结构体
  • 原文地址:https://www.cnblogs.com/yezekun/p/3925702.html
Copyright © 2020-2023  润新知