首先这题的两条线不相交的限制可以去掉,因为如果相交的话把点换一换是不影响最终结果的。

剩下的费用流建图是显然的,把点拆为两个,建立超级源点s和源点ss汇点t,连边(s,ss,2,0). 对于每个点,连边(ss,i,1,0), (i,i',1,1),(i',t,1,0).

这样跑一遍费用流就行了,然而此题的边数可以达到n^2.无疑是OLE的。需要优化。

容易发现,对于点(i,j),(j,k),(i,k).如果这些点都可以互相到达的话,那么(i,k)这条边是不必要的。因为通过j到达k是不会比结果劣的。

所以启发我们将点按x坐标以第一关键字排序,y第二关键字排序。对于相同的列,选择大于前一列的y坐标且最小的点连边。

这样建边之后还存在一个问题,可能有个点两个吃豆人都需要经过,于是再建边(i,i',1,0),(i',j,2,0).

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi 3.1415926535
# define eps 1e-
# define MOD
# define INF
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<,l,mid
# define rch p<<|,mid+,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
int res=, flag=;
char ch;
if((ch=getchar())=='-') flag=;
else if(ch>=''&&ch<='') res=ch-'';
while((ch=getchar())>=''&&ch<='') res=res*+(ch-'');
return flag?-res:res;
}
void Out(int a) {
if(a<) {putchar('-'); a=-a;}
if(a>=) Out(a/);
putchar(a%+'');
}
const int N=;
//Code begin... struct Node{int x, y;}node[];
struct Edge{int to, next, cap, flow, cost;}edge[];
int head[N], tol, pre[N], dis[N], nn;
bool vis[N];
queue<int>q; void init(int n){nn=n; tol=; mem(head,-);}
void addedge(int u, int v, int cap, int cost){
edge[tol].to=v; edge[tol].cap=cap; edge[tol].cost=cost; edge[tol].flow=; edge[tol].next=head[u]; head[u]=tol++;
edge[tol].to=u; edge[tol].cap=; edge[tol].cost=-cost; edge[tol].flow=; edge[tol].next=head[v]; head[v]=tol++;
}
bool spfa(int s, int t){
FO(i,,nn) dis[i]=INF, vis[i]=false, pre[i]=-;
dis[s]=; vis[s]=true; q.push(s);
while (!q.empty()) {
int u=q.front(); q.pop(); vis[u]=false;
for (int i=head[u]; i!=-; i=edge[i].next) {
int v=edge[i].to;
if (edge[i].cap>edge[i].flow&&dis[v]>dis[u]+edge[i].cost) {
dis[v]=dis[u]+edge[i].cost; pre[v]=i;
if (!vis[v]) vis[v]=true, q.push(v);
}
}
}
if (pre[t]==-) return false;
else return true;
}
int minCostMaxflow(int s, int t, int &cost){
int flow=; cost=;
while (spfa(s,t)) {
int Min=INF;
for (int i=pre[t]; i!=-; i=pre[edge[i^].to]) {
if (Min>edge[i].cap-edge[i].flow) Min=edge[i].cap-edge[i].flow;
}
for (int i=pre[t]; i!=-; i=pre[edge[i^].to]) {
edge[i].flow+=Min; edge[i^].flow-=Min; cost+=edge[i].cost*Min;
}
flow+=Min;
}
return flow;
}
bool comp(Node a, Node b){
if (a.x==b.x) return a.y<b.y;
else return a.x<b.x;
}
int main ()
{
int n, s, ss, t;
scanf("%d",&n);
s=; ss=*n+; t=*n+;
init(t+);
addedge(s,ss,,);
FOR(i,,n) {
scanf("%d%d",&node[i].x,&node[i].y);
addedge(ss,i,,); addedge(i,n+i,,-); addedge(i,n+i,,); addedge(n+i,t,,);
}
sort(node+,node+n+,comp);
FOR(i,,n) {
int mi=INF, now=;
FOR(j,i+,n) {
if (now==node[j].x||node[j].y<node[i].y) continue;
if (node[j].y<mi) mi=node[j].y, now=node[j].x, addedge(n+i,j,,);
}
}
int ans;
minCostMaxflow(s,t,ans);
printf("%d\n",-ans);
return ;
}

BZOJ 1930 吃豆豆(费用流)的更多相关文章

  1. bzoj 1930: [Shoi2003]pacman 吃豆豆 [费用流]

    1930: [Shoi2003]pacman 吃豆豆 题意:两个PACMAN吃豆豆.一开始的时候,PACMAN都在坐标原点的左下方,豆豆都在右上方.PACMAN走到豆豆处就会吃掉它.PACMAN行走的 ...

  2. [bzoj 1449] 球队收益(费用流)

    [bzoj 1449] 球队收益(费用流) Description Input Output 一个整数表示联盟里所有球队收益之和的最小值. Sample Input 3 3 1 0 2 1 1 1 1 ...

  3. BZOJ.2597.[WC2007]剪刀石头布(费用流zkw)

    BZOJ 洛谷 \(Description\) 给定一张部分边方向已确定的竞赛图.你需要给剩下的边确定方向,使得图中的三元环数量最多. \(n\leq100\). \(Solution\) 这种选择之 ...

  4. bzoj 1070: [SCOI2007]修车 费用流

    1070: [SCOI2007]修车 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2785  Solved: 1110[Submit][Status] ...

  5. BZOJ 3171 循环格(费用流)

    题意 一个循环格就是一个矩阵,其中所有元素为箭头,指向相邻四个格子.每个元素有一个坐标(行,列),其中左上角元素坐标为(0,0).给定一个起始位置(r,c),你可以沿着箭头防线在格子间行走.即如果(r ...

  6. BZOJ 1070 修车 【费用流】

    Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同 的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序, ...

  7. BZOJ 1927 星际竞速(费用流)

    考虑费用流,题目要求走n个点都走完且恰好一次,显然流量的限制为n. 建立源点s和汇点t,并把每个星球拆成两个点i和i',分别表示已到达该点和经过该点. 对于能力爆发,建边(s,i',1,w). 对应高 ...

  8. BZOJ 1221 软件开发(费用流)

    容易看出这是显然的费用流模型. 把每天需要的餐巾数作为限制.需要将天数拆点,x’表示每天需要的餐巾,x’’表示每天用完的餐巾.所以加边 (s,x',INF,0),(x'',t,INF,0). 餐巾可以 ...

  9. bzoj 1520 [POI2006]Szk-Schools 费用流

    [POI2006]Szk-Schools Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 743  Solved: 381[Submit][Status][ ...

随机推荐

  1. 成都Uber优步司机奖励政策(2月2日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  2. 天津市人民优步Uber司机奖励政策(9月14日~9月20日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  3. HI-2110的657sp3版本应用笔记之TUP

    1. TUP是什么? TUP是华为的搞的一套封装了标准Coap的函数,底层是Coap,上层是华为封装的一层收发函数,用来简化Coap的收发流程,最终只用6个函数搞定,不用懂Coap就可以的. 2. T ...

  4. 游戏人工智能 读书笔记 (四) AI算法简介——Ad-Hoc 行为编程

    本文内容包含以下章节: Chapter 2 AI Methods Chapter 2.1 General Notes 本书英文版: Artificial Intelligence and Games ...

  5. uvaoj 489 - Hangman Judge(逻辑+写代码能力)

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  6. Qt-序列号生成器

    一直想做一个序列号的生成器,今天终于有了开始了,目前只有读取硬件生成,还没有做生成序列号的规则. 目前实现的功能就是读取系统磁盘卷加上CPU ID 和自己的加密字符串,在利用MD5加密,转换成标准32 ...

  7. [C++]STL中的容器

    C++11 STL中的容器 一.顺序容器: vector:可变大小数组: deque:双端队列: list:双向链表: forward_list:单向链表: array:固定大小数组: string: ...

  8. JAVA 面试须知

    本篇文章会对面试中常遇到的Java技术点进行全面深入的总结,帮助我们在面试中更加得心应手,不参加面试的同学也能够借此机会梳理一下自己的知识体系,进行查漏补缺. 1. Java中的原始数据类型都有哪些, ...

  9. ArrayList与LinkedList的普通for循环遍历

    对于大部分Java程序员朋友们来说,可能平时使用得最多的List就是ArrayList,对于ArrayList的遍历,一般用如下写法: public static void main(String[] ...

  10. 浪在ACM新春大作战

    题目链接: # Name 补题状态 A Memory and Crow 已补 B Memory and Trident 已补 C Memory and De-Evolution 已补 D Memory ...