BZOJ 3511 土地划分

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=3511

题目分析:

  看上去和前面的人员雇佣以及小M种田都很像。

  最小割模型来求最大值,一般都是考虑怎样构图使得满足一个组合能被表示出来,而且当满足一个组合的时候,能产生或失去所需的效益。[割掉的是不要的]

  我们将s与1相连,连为INF,这样就不会被割,n向t连边,同理。

  因为1和n会有边连接,所以我们才多建出了节点s,t。

  然后对于每个点i,s向i连wa[i],i向t连wb[i],这样就满足了第一条性质。

  对于ea,eb,ec的弄法,我们就先从s向u和向v连ea/2,从u和v向t连eb/2,然后在uv之间连一条双向的ea/2+eb/2+ec的边。

  这样连边就能满足第二条性质了,反正就是脑补一下各种割法,就发现它奥妙重重,十分正确。

  然后可以缩一下边,把s->i的边集以及i->t的合并一下[优化一下常数]。

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=10010;
const int maxm=40010;
const int INF=0x3f3f3f3f;

struct Node{
    int data,next,low; 
}node[maxm*2+maxn*4];

#define now node[point].data
#define www node[point].low
#define then node[point].next

int n,m,cnt;
int s,t,ans;
int wa[maxn],wb[maxn];
int stoi[maxn],itot[maxn];
int cur[maxn],head[maxn];
int dis[maxn],que[maxn];

void add(int u,int v,int w){
    node[cnt].data=v;node[cnt].next=head[u];node[cnt].low=w;head[u]=cnt++;
    node[cnt].data=u;node[cnt].next=head[v];node[cnt].low=0;head[v]=cnt++;
}

void add2(int u,int v,int w){
    node[cnt].data=v;node[cnt].next=head[u];node[cnt].low=w;head[u]=cnt++;
    node[cnt].data=u;node[cnt].next=head[v];node[cnt].low=w;head[v]=cnt++;
}

bool BFS(){
    memset(dis,-1,sizeof(dis));
    int H=0,T=1;que[1]=s;dis[s]=0;
    while(H<T){
        H++;
        for(int point=head[que[H]];point!=-1;point=then)
            if(www && dis[now]<0){
                dis[now]=dis[que[H]]+1;
                que[++T]=now;
            }
    }
    return dis[t]>0;
}

int dfs(int x,int low){
    if(x==t) return low;
    int Low;
    for(int &point=cur[x];point!=-1;point=then)
        if(www && dis[now]==dis[x]+1){
            Low=dfs(now,min(low,www));
            if(Low){
                www-=Low,node[point^1].low+=Low;
                return Low;
            }
        }
    return 0;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("3511.in","r",stdin);
    freopen("3511.out","w",stdout);
#endif

    int u,v,Ea,Eb,Ec;

    scanf("%d%d",&n,&m);
    t=n+1;
    for(int i=s;i<=t;i++) head[i]=-1;
    for(int i=2;i<n;i++) scanf("%d",&wa[i]),stoi[i]+=(wa[i]<<1);
    for(int i=2;i<n;i++) scanf("%d",&wb[i]),itot[i]+=(wb[i]<<1);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d%d%d",&u,&v,&Ea,&Eb,&Ec);
        add2(u,v,Ea+Eb+(Ec<<1));
        stoi[u]+=Ea,stoi[v]+=Ea;
        itot[u]+=Eb,itot[v]+=Eb;
    }
    for(int i=1;i<=n;i++)
        ans+=stoi[i]+itot[i];
    stoi[1]=itot[n]=INF;
    for(int i=1;i<=n;i++)
        add(s,i,stoi[i]),add(i,t,itot[i]);
    
    int flag;
    while(BFS()){
        memcpy(cur,head,sizeof(head));
        while(flag=dfs(s,INF))
            ans-=flag;
    }
    
    ans>>=1;
    printf("%d",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Robert-Yuan/p/5223274.html