zoukankan      html  css  js  c++  java
  • 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;
    }
    

  • 相关阅读:
    Linux文件属性
    [Oracle] Listener的动态注册
    jQuery easyUI Pagination控件自定义div分页(不用datagrid)
    桂林电子科技大学出校流量控制器Android版1.0.0
    php使用check box
    Python windows ping
    Python selenium chrome 环境配置
    Linux wget auto login and backup database
    PyQt4 ShowHMDB show sqlite3 with QTableWidget summary
    PyQt4 py2exe 打包 HardwareManager
  • 原文地址:https://www.cnblogs.com/yezekun/p/3925702.html
Copyright © 2011-2022 走看看