Happiness解题思路

类似于上面所说的,我们定义如果和 \(S\) 相连说明我们选择文科,如果和 \(T\) 相连就说明选的是理科。

考虑如何建边,肯定是每一个人都建若干个点吧,如果一个点表示我这个人选了理科,那么他要向文科建边,边权是文科的代价,如果我这个人选了文科,就向理科连边,边权是理科的代价。那么如何处理两个人之间同时学文科和同时学理科的代价呢?

短时间内没有想到,但是之后看完题解就会了,比如说如果我们是对于两个东西都要选文科,那么我们有一个办法,就是把文科点连向一个另外的点,边权为如果他们两个都选文科的代价,然后这个点向那两个点都连上正无穷的边,说明这个是断不掉的,那么这就说明,另外两个点但凡有一个东西连向了 \(T\) 他都必须被割掉。然后跑一遍最小割就可以了。

#include <bits/stdc++.h>
using namespace std;
template <typename T>inline void read(T& t){t=0; register char ch=getchar(); register int fflag=1;while(!('0'<=ch&&ch<='9')) {if(ch=='-') fflag=-1;ch=getchar();}while(('0'<=ch&&ch<='9')){t=t*10+ch-'0'; ch=getchar();} t*=fflag;}
template <typename T,typename... Args> inline void read(T& t, Args&... args) {read(t);read(args...);}
const int inf=0x3f3f3f3f;

const int M=9e5,N=5e5+10;

template<typename T>
struct FlowGragh{
    int n,s,t,cnt=1;
    struct Edge{
        int from,to;
        T flow;
        int nxt;
    }e[M];
    int head[N],dis[N],cur[N];
    void adde(int u,int v,T val,T rval=0){
        e[++cnt]={u,v,val,head[u]}; head[u]=cnt;
        e[++cnt]={v,u,rval,head[v]}; head[v]=cnt;
    }
    void intt(int nn,int ss,int tt){
        n=nn;s=ss;t=tt;
        cnt=1;
        memset(head,0,sizeof(head));
    }
    bool bfs(){
        queue<int>Q;
        memset(dis,0,sizeof(dis));
        Q.push(s); dis[s]=1; cur[s]=head[s];
        while(!Q.empty()){
            int u=Q.front(); Q.pop();
            for(int i=head[u];i;i=e[i].nxt){
                int v=e[i].to;
                if(!dis[v]&&e[i].flow){
                    Q.push(v);
                    dis[v]=dis[u]+1;
                    cur[v]=head[v];
                }
            }
        }
        return dis[t];
    }
    T dfs(int u,T flow){
        if(u==t) return flow;
        T rest=flow;
        for(int i=cur[u];i;i=cur[u]=e[i].nxt){
            int v=e[i].to;
            if(dis[v]==dis[u]+1&&e[i].flow){
                int fflow=dfs(v,rest<e[i].flow?rest:e[i].flow);
                e[i].flow-=fflow;
                rest-=fflow;
                e[i^1].flow+=fflow;
                if(!rest) break;
            }
        }
        if(rest==flow) dis[u]=-1;
        return flow-rest;
    }
    T dinic(){
        T res=0,tot=0;
        while(bfs())
            while(res=dfs(s,1e8)) tot+=res;
        return tot;
    }
};

int n,m,s=5e5+1,t=5e5+2;
long long sum=0;
FlowGragh<int>A;

int number(int x,int y){return (x-1)*m+y;}

int main(){
    read(n,m);
    A.intt(t,s,t);
    int pcnt=n*m;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j){
            int val;
            read(val);
            sum+=val;
            A.adde(s,number(i,j),val);
        }
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j){
            int val;
            read(val);
            sum+=val;
            A.adde(number(i,j),t,val);
        }
    for(int i=1;i<n;++i)
        for(int j=1;j<=m;++j){
            int val;
            read(val);
            sum+=val;
            ++pcnt;
            A.adde(s,pcnt,val);
            A.adde(pcnt,number(i,j),inf);
            A.adde(pcnt,number(i+1,j),inf);
        }
    for(int i=1;i<n;++i)
        for(int j=1;j<=m;++j){
            int val;
            read(val);
            sum+=val;
            ++pcnt;
            A.adde(pcnt,t,val);
            A.adde(number(i,j),pcnt,inf);
            A.adde(number(i+1,j),pcnt,inf);
        }
    for(int i=1;i<=n;++i)
        for(int j=1;j<m;++j){
            int val;
            read(val);
            sum+=val;
            ++pcnt;
            A.adde(s,pcnt,val);
            A.adde(pcnt,number(i,j),inf);
            A.adde(pcnt,number(i,j+1),inf);
        }
    for(int i=1;i<=n;++i)
        for(int j=1;j<m;++j){
            int val;
            read(val);
            sum+=val;
            ++pcnt;
            A.adde(pcnt,t,val);
            A.adde(number(i,j),pcnt,inf);
            A.adde(number(i,j+1),pcnt,inf);
        }
    cout<<sum-A.dinic()<<endl;
    return 0;
}
/*
是谁挥霍的时光啊,是谁苦苦的奢望啊

这不是一个问题,也不需要你的回答

No answer. 
*/
posted @ 2022-08-23 07:46  Mercury_City  阅读(11)  评论(0编辑  收藏  举报