• hdu1565 网络流或状态压缩DP


    对于网络流有一个定理:

    最小点权覆盖集=最大网络流;

    最大点权独立集=总权值-最小点权覆盖集;

    网络流解法代码如下:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define N 1010
    #define M 50010
    #define inf 1<<30
    using namespace std;
    struct Edge{
        int to,val,next;
    }edge[M];
    int index[N],d[N],gap[N],e;
    void addedge(int from,int to,int val)
    {
        edge[e].to=to;
        edge[e].val=val;
        edge[e].next=index[from];
        index[from]=e++;
        edge[e].to=from;
        edge[e].val=0;
        edge[e].next=index[to];
        index[to]=e++;
    }
    int source,des,n,m;
    //n is the number of point
    int dfs(int pos,int flow)
    {
        if(pos==des)
            return flow;
        int i,j,v,val,lv,mind,c;
        mind=n-1;//初始最小标号为n-1
        lv=flow;
        for(i=index[pos];i!=-1;i=edge[i].next)
        {
            v=edge[i].to;
            val=edge[i].val;
            if(val)
            {
                if(d[v]+1==d[pos])
                {
                    c=min(lv,val);//对于该点的最小可行流
                    c=dfs(v,c);
                    edge[i].val-=c;//更新剩余图
                    edge[i^1].val+=c;
                    lv-=c;
                    if(d[source]>=n)return flow-lv;
                    if(lv==0) break;
                }
                if(d[v]<mind)mind=d[v];//找出与pos相连的点的最小标号
            }
        }
        if(lv==flow)//没有找到增广路劲,进行标号更新
        {
            --gap[d[pos]];
            if(!gap[d[pos]])
                d[source]=n;
            d[pos]=mind+1;
            ++gap[d[pos]];
        }
        return flow-lv;
    }
    int sap(int st,int de)
    {
        source=st;
        des=de;
        memset(d,0,sizeof(d));
        memset(gap,0,sizeof(gap));
        gap[0]=n;//初始标号为0的有n个.
        int ans=0;
        while(d[st]<n)
        {
            ans+=dfs(st,inf);
            //cout<<d[st]<<endl;
        }
        return ans;
    }
    void init()
    {
        e=0;
        memset(index,-1,sizeof(index));
    }
    int pos(int a,int b)
    {
        return (a-1)*m+b;
    }
    int main()
    {
        int t,i,j;
        while(scanf("%d",&m)!=EOF)
        {
            
            init();
            int w;
            int sum=0;
            for(i=1;i<=m;i++)
                for(j=1;j<=m;j++)
                {
                    scanf("%d",&w);
                    sum+=w;
                    if((i+j)%2==0)
                    {
                        addedge(0,pos(i,j),w);
                        if(i<m)
                            addedge(pos(i,j),pos(i+1,j),inf);
                        if(j<m)
                            addedge(pos(i,j),pos(i,j+1),inf);
                        if(i>1)
                            addedge(pos(i,j),pos(i-1,j),inf);
                        if(j>1)
                            addedge(pos(i,j),pos(i,j-1),inf);
                    }
                    else
                        addedge(pos(i,j),m*m+1,w);
                }
                n=m*m+2;
            printf("%d
    ",sum-sap(0,n-1));
        }
        return 0;
    }

     状态压缩解法:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int s[1<<21];
    int map[22][22];
    int dp[2][1<<21];
    int main()
    {
        int n,i,j,t,k,num=0;;
        n=1<<21;
        for(i=0;i<=n;i++)//记录可行状态
            if((i&(i<<1))==0)
                s[num++]=i;
        while(scanf("%d",&n)!=EOF)
        {
            for(i=0;i<n;i++)
                for(j=0;j<n;j++)
                    scanf("%d",&map[i][j]);
            int p=0;
            memset(dp,0,sizeof(dp));
            for(i=0;i<n;i++)//枚举每一行
            {
                p^=1;//进行滚动数组
                for(j=0;j<num;j++)//枚举每行的所有状态
                {
                    if(s[j]>(1<<n))
                        break;
                    int sum=0;
                    for(k=0;k<n;k++) if(s[j]&(1<<k)) sum+=map[i][k];//记录该状态值
                    for(k=0;k<num;k++)//枚举已经得到的状态转移到该状态能到的最大值
                    {
                        if(s[k]>(1<<n))
                            break;
                        if(!(s[k]&s[j]))
                            dp[p][s[j]]=max(dp[p][s[j]],dp[1-p][s[k]]+sum);
                    }
                }
            }
            int ans=0;
            for(i=0;i<num&&s[i]<=(1<<n);i++)//寻找答案
                ans=max(ans,dp[p][s[i]]);
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    Redis主从复制
    Centos6克隆虚拟机改IP和mac地址
    Liunx中ERROR 2002 (HY000) Can't connect to local MySQL server through socket 'varlibmysqlmysql.sock' (2)报错
    linux安装redis
    每天五分钟带你了解Redis
    sqiud --ACL控制应用、sarg日志分析、反向代理
    squid--透明代理
    Squid--传统代理
    Tomcat+Nginx实现动静分离
    -bash: nginx: 未找到命令/没有这个文件
  • 原文地址:https://www.cnblogs.com/wangfang20/p/3178550.html
Copyright © 2020-2023  润新知