BZOJ3511 土地划分 题解&代码

pkusc发现自己不会费用流233333于是两天速成费用流【然而这是一道最小割(最大流QwQ

题意:

给出n个点m条边,并设定:

点x在被划分至集合A时获得权值A[x],否则即被划分至集合B并获得权值B[x];

边(x,y)连接的x和y均属于集合A时获得权值ea,均属于集合B时获得权值eb,否则获得权值-ec。

题解:这题…反正我是没自己建出图来。

对于点x,从S(代表集合A)向x连容量为va的边,从x向T(代表集合B)连容量为vb的边。

对于边(x,y),从S向x和y分别连容量为ea/2的边,从x和y向T分别连容量为eb/2的边,然后x和y中间互相连两条容量为ea/2+eb/2+ec的边。

这样的话,图中最大流就是划分这个图的最小花费。

于是答案就是权值和减去最小割(最大流)

反正换我肯定做不出来orz还是智商受到了限制

/**************************************************************
    Problem: 3511
    User: Rainbow6174
    Language: C++
    Result: Accepted
    Time:1612 ms
    Memory:6744 kb
****************************************************************/

#include <cstdio>
#include<iostream>
#include <algorithm>
#define LL long long
using namespace std;
const int maxn = 10005;
const int maxm = 40005;
const int maxq = 50005;
const int inf = 0x3f3f3f3f;
int n,m,v,head[maxn],cur[maxn],cnt,st,ed,deep[maxn],q[maxq];
LL ans;
struct edge{
    int v,w,next;
} e[4*maxn+10*maxm];
void add(int u, int v, int w,int rw)
{
    e[cnt]=(edge){v,w,head[u]};
    head[u]=cnt++;
    e[cnt]=(edge){u,rw,head[v]};
    head[v]=cnt++;
}
bool bfs(void)
{
    for(int i=st; i<=ed; i++)
        deep[i]=-1;
    int h=0,t=0;
    deep[st]=1;
    q[t++]=st;
    while(h != t)
    {
        int u = q[h++];
        for(int i=head[u]; i!=-1; i=e[i].next)
            if(e[i].w && deep[e[i].v]==-1)
            {
                deep[e[i].v]=deep[u]+1;
                if(e[i].v==ed) return true;
                q[t++]=e[i].v;
            }
    }
    return false;
}
int dfs(int x,int flow)
{
    if(x==ed)return flow;
    int left=flow;
    for(int i=cur[x]; i!=-1; i=e[i].next)
        if(e[i].w && deep[e[i].v]==deep[x]+1)
        {
            int tmp=dfs(e[i].v,min(left,e[i].w));
            left-=tmp;
            e[i].w-=tmp;
            e[i^1].w+=tmp;
            if(e[i].w)cur[x]=i;
            if(!left)return flow;
        }
    if(left==flow)deep[x]=-1;
    return flow-left;
}
LL dinic(void)
{
    LL ret=0;
    while(bfs())
    {
        for(int i=st; i<=ed; i++)
            cur[i]=head[i];
        ret+=(LL)dfs(st,inf);
    }
    return ret;
}
int main(void)
{
    scanf("%d%d",&n,&m);
    st=0;ed=n+1;
    for(int i=st; i<=ed; i++)
        head[i]=-1;
    add(st,1,inf,0);
    add(n,ed,inf,0);
    for(int i=2; i<n; i++)
    {
        scanf("%d",&v);v*=2;
        add(st,i,v,0);
        ans+=v;
    }
    for(int i=2; i<n; i++)
    {
        scanf("%d",&v);v*=2;
        add(i,ed,v,0);
        ans+=v;
    }
    for(int i=1; i<=m; i++)
    {
        int x,y,ea,eb,ec;
        scanf("%d%d",&x,&y);
        scanf("%d%d%d",&ea,&eb,&ec);
        add(st,x,ea,0);
        add(st,y,ea,0);
        add(x,ed,eb,0);
        add(y,ed,eb,0);
        add(x,y,ea+eb+ec*2,ea+eb+ec*2);
        ans+=(ea+eb)*2;
    }
    ans-=dinic();
    printf("%lld\n",ans/2);
    return 0;
}
时间: 2024-09-30 09:02:53

BZOJ3511 土地划分 题解&代码的相关文章

洛谷 P2194 HXY烧情侣【Tarjan缩点】 分析+题解代码

洛谷 P2194 HXY烧情侣[Tarjan缩点] 分析+题解代码 题目描述: 众所周知,HXY已经加入了FFF团.现在她要开始喜(sang)闻(xin)乐(bing)见(kuang)地烧情侣了.这里有n座电影院,n对情侣分别在每座电影院里,然后电影院里都有汽油,但是要使用它需要一定的费用.m条单向通道连接相邻的两对情侣所在电影院.然后HXY有个绝技,如果她能从一个点开始烧,最后回到这个点,那么烧这条回路上的情侣的费用只需要该点的汽油费即可.并且每对情侣只需烧一遍,电影院可以重复去.然后她想花尽

洛谷P2832 行路难 分析+题解代码【玄学最短路】

洛谷P2832 行路难 分析+题解代码[玄学最短路] 题目背景: 小X来到了山区,领略山林之乐.在他乐以忘忧之时,他突然发现,开学迫在眉睫 题目描述: 山区有n座山.山之间有m条羊肠小道,每条连接两座山,只能单向通过,并会耗费小X一定时间. 小X现在在1号山,他的目的是n号山,因为那里有火车站. 然而小X的体力是有限的.他每通过一条羊肠小道,就会变得更疲劳,导致他通过任意一条羊肠小道的时间都增加1. 输入格式: 第一行两个数,n,m 第2行到第m+1行,每行3个数A,B,C,表示A.B之间有一条

Theatre Square 题解代码

Theatre Square CodeForces - 1A 水题水题... 最开始的程序是这个,可是AC不了我也不知道为什么......QAQ... #include <stdio.h>#include<stdlib.h>int main(){    int m,n,a,ans,tmp,k,h,tep,i,j;    scanf("%d %d %d",&m,&n,&a);    if(m%a==0)    {        if(n%a

leetcode 题解代码整理 36-40题

Valid Sudoku Determine if a Sudoku is valid, according to: Sudoku Puzzles - The Rules. The Sudoku board could be partially filled, where empty cells are filled with the character '.'. A partially filled sudoku which is valid. 判断数独当前状态是否合法 class Solut

leetcode 题解代码整理 1-5题

Two Sum Given an array of integers, find two numbers such that they add up to a specific target number. The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please no

leetcode 题解代码整理 31-35题

Next Permutation Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers. If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending orde

leetcode 题解代码整理 21-25题

Merge Two Sorted Lists Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists. 合并两个有序链表 /** * Definition for singly-linked list. * struct ListNode { * int val; * Li

leetcode 题解代码整理 6-10题

ZigZag Conversion The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility) P A H N A P L S I I G Y I R And then read line by line

2016 年宁波工程学院第七届ACM校赛题解报告

2016 年宁波工程学院第七届ACM校赛题解报告 本题解代码直接为比赛代码,仅供参考. A,B,C,D,G,H,J,K,L,M 来自 Ticsmtc 同学. F 来自 Gealo 同学. E,I 来自Alex 学长. Promblem A :    Two Sum 时间限制: 1 Sec  内存限制: 64 MB 题目描述: 给出n个数,另外给出?个整数S,判断是否可以从中取出2个数,使得这两个数的和是S. 输入: 第?行有个整数T(1 <= T <= 10),代表数据组数. 对于每组数据,第