zoukankan      html  css  js  c++  java
  • bzoj4873(最大权闭合子图)

    今天学了最大权闭合子图。。然后找了这道题,发现完全不会。。。。。

    看了题解发现这种有诸如选了一个就一定要选另外的一些的限制又要求最优值的题有的可以转化成最大权闭合子图,

    这个题我们首先想到不会选相交的区间,

    因为那样代价多算了一遍又不会增加价值。然后就是选一些区间,就有了一个经典的限制:

    如果选了区间[i,j]就一定要选[i+1,j]和[i,j-1];

    关于代价的处理我们可以对每一个[i,i]连到一个权值为-m*a[i]*a[i]的点,然后把每个[i,i]减去a[i],这里关键是把题意理解好就行了;

    //图论模型,难在建图;
    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn=111,maxa=1000,inf=1e9;
    int D[maxn*maxn+maxa],t=1,n,m,S,T,sum,last[maxn*maxn+maxa],a[maxn],d[maxn][maxn],num[maxn][maxn];
    struct edg{
        int nxt,to,f;
    }e[maxn*maxn*6+maxa*2];
    void add(int x,int y,int z){
        ++t;e[t].nxt=last[x];last[x]=t;e[t].to=y;e[t].f=z;
        ++t;e[t].nxt=last[y];last[y]=t;e[t].to=x;e[t].f=0;
    }
    int q[maxn*maxn+maxa],head,tail;
    int bfs(){
        head=tail=0;memset(D,-1,sizeof(D));
        q[++tail]=S;D[S]=0;
        while(head<tail){
            int u=q[++head];
            for(int i=last[u];i;i=e[i].nxt){
                int v=e[i].to;
                if(e[i].f&&D[v]==-1){
                    D[v]=D[u]+1;q[++tail]=v;
                }
            }
        }
        return D[T]!=-1;
    }
    int dfs(int x,int h){
        if(x==T){return h;}
        int tmp=0,cp;
        for(int i=last[x];i;i=e[i].nxt){
            int v=e[i].to;
            if(e[i].f&&D[v]==D[x]+1){
                cp=dfs(v,min(h-tmp,e[i].f));
                e[i].f-=cp;e[i^1].f+=cp;tmp+=cp;
            }
        }
        if(!tmp)D[x]=-2;
        return tmp;
    }
    int dinic(){
        int pp,res=0;
        while(bfs()){
            while(pp=dfs(S,inf))res+=pp;
        }
        return res;
    }
    int main(){
        cin>>n>>m;
        for(int i=1;i<=n;++i)scanf("%d",&a[i]);
        S=1;T=S+maxa+n*n+1;
        for(int i=1;i<=maxa;++i)add(S+i,T,m*i*i);
        int cnt=0;
        for(int i=1;i<=n;++i)
          for(int j=i;j<=n;++j){
            scanf("%d",&d[i][j]);
            ++cnt,num[i][j]=S+maxa+cnt;
        }
        for(int i=1;i<=n;++i)
          for(int j=i;j<=n;++j){
            if(i==j){
                d[i][j]-=a[i];
                add(num[i][j],S+a[i],inf);
            }
            else{
                add(num[i][j],num[i+1][j],inf);
                add(num[i][j],num[i][j-1],inf);
            }
            if(d[i][j]>0){
                sum+=d[i][j];
                add(S,num[i][j],d[i][j]);
            }
            else{
                add(num[i][j],T,-d[i][j]);
            }
        }
        printf("%d",sum-dinic());
        //system("pause");
        return 0;
    }
  • 相关阅读:
    指针的学习
    (转)c & c++内存分配
    C++实现String
    c& c++笔试题
    appium python api收集
    公司python入职培训流程
    app端性能测试笔记
    h5 测试关注点
    robot framework 牛刀一试
    adb 安装apk 报错:Failure [INSTALL_FAILED_INVALID_URI]
  • 原文地址:https://www.cnblogs.com/dibaotianxing/p/8277477.html
Copyright © 2011-2022 走看看