BZOJ 3511: 土地划分 最小割

title

BZOJ 3511
LUOGU 4210
Description

Y国有N座城市,并且有M条双向公路将这些城市连接起来,并且任意两个城市至少有一条路径可以互达。
Y国的国王去世之后,他的两个儿子A和B都想成为新的国王,但他们都想让这个国家更加安定,不会用武力解决问题。
于是他们想将这个国家分成两个小国家A国和B国。现在,A拥有1号城市,B拥有N号城市,其他的城市还尚未确定归属哪边(划分之后的国家内部城市可以不连通)。
由于大家都想让国家变得更好,而某些城市的人民愿意国王的A儿子作为他们的领袖,而某些城市更看好B,而为了交通的便捷,如果划分后的公路连接两个同一个国家的城市,那么更利于城市之间的交流。于是大臣们设计了一种对土地划分的评分机制,具体如下:

  1. 对于城市i,如果它划分给A国,将得到VA[i]的得分;划分给B国,将得到VB[i]的得分。
  2. 对于一条公路i,如果它连接两个A国的城市,将得到EA[i]的得分;连接两个B国的城市,将得到EB[i]的得分;否则,这条公路将失去意义,将扣除EC[i]的得分。
    现请你找到最优的土地划分,使得这种它的评分最高。

Input

第一行包含两个整数N,M,含义如问题描述所示。
接下来一行N-2个非负整数,表示VA[2..N-1]。
接下来一行N-2个非负整数,表示VB[2..N-1]。
接下来M行,每行五个非负整数描述一条公路:X Y EA[i] EB[i] EC[i],含义如问题描述所示。

Output

输出有且仅有一个整数,表示最高评分。

Sample Input

3 3
8
9
1 2 2 6 2
2 3 8 5 7
1 3 9 4 1

Sample Output

11
【样例说明】
A国仅有1号点,B国有2号和3号点。
评分=VB[2]+EB[2]-EC[1]-EC[3]=9+5-2-1=11。

HINT

【数据说明】
数据点 N M 备注
1-2 <=20 <=200 无
3-4 <=5000 <=10000 VA、VB、EA、EB均为0
5-6 <=5000 <=10000 EC均为0
7-10 <=10000 <=40000 无
保证运算过程中及最终结果不超过32位带符号整数类型的表示范围

analysis

说得再清楚也没有我大 menci\(blog\) 清楚了吧,毕竟这道题堪称最小割模型集大成者(也就是套路到家了,文理分科 2.0 版),就这样了。

code

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+10,maxm=3e5+10,inf=0x3f3f3f3f;

char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1, ch=getchar();
    while (!isdigit(ch) && ch^'-') ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}

template<typename T>inline void write(T x)
{
    if (!x) { putchar('0'); return ; }
    if (x<0) putchar('-'), x=-x;
    T num=0, ch[20];
    while (x) ch[++num]=x%10+48, x/=10;
    while (num) putchar(ch[num--]);
}

int ver[maxm<<1],edge[maxm<<1],Next[maxm<<1],head[maxn],len=1;
inline void add(int x,int y,int z)
{
    ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
    ver[++len]=x,edge[len]=0,Next[len]=head[y],head[y]=len;
}

int s,t;
int dist[maxn];
inline bool bfs()
{
    queue<int>q;
    memset(dist,0,sizeof(dist));
    q.push(s),dist[s]=1;
    while (!q.empty())
    {
        int x=q.front();
        q.pop();
        for (int i=head[x]; i; i=Next[i])
        {
            int y=ver[i];
            if (edge[i] && !dist[y])
            {
                dist[y]=dist[x]+1;
                if (y==t) return 1;
                q.push(y);
            }
        }
    }
    return 0;
}

inline int get(int x,int low)
{
    if (x==t) return low;
    int tmp=low;
    for (int i=head[x]; i; i=Next[i])
    {
        int y=ver[i];
        if (edge[i] && dist[y]==dist[x]+1)
        {
            int a=get(y,min(tmp,edge[i]));
            if (!a) dist[y]=0;
            edge[i]-=a;
            edge[i^1]+=a;
            if (!(tmp-=a)) break;
        }
    }
    return low-tmp;
}

int a[maxn],b[maxn];
int main()
{
    int n,m;
    read(n);read(m);
    a[1]=inf,a[n]=0;
    b[1]=0,b[n]=inf;
    s=0,t=n+1;
    int sum=0;
    for (int i=2,x; i<n; ++i) read(x),a[i]=x<<1,sum+=a[i];
    for (int i=2,x; i<n; ++i) read(x),b[i]=x<<1,sum+=b[i];
    for (int i=1,x,y,ea,eb,ec; i<=m; ++i)
    {
        read(x),read(y),read(ea),read(eb),read(ec);
        a[x]+=ea, a[y]+=ea, sum+=ea<<1;
        b[x]+=eb, b[y]+=eb, sum+=eb<<1;
        add(x,y,ea+eb+(ec<<1)),add(y,x,ea+eb+(ec<<1));
    }
    for (int i=1; i<=n; ++i) add(s,i,a[i]),add(i,t,b[i]);
    int ans=0;
    while (bfs()) ans+=get(s,inf);
    write((sum-ans)>>1),puts("");
    return 0;
}

转载于:https://www.cnblogs.com/G-hsm/p/11323226.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值