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

剩下的费用流建图是显然的,把点拆为两个,建立超级源点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 ;
}

最新文章

  1. BZOJ1269——[AHOI2006]文本编辑器editor
  2. SQL INSERT INTO 语句
  3. 11——在operator=中处理自我赋值
  4. Android 简易XML解析
  5. STL学习系列七:优先级队列priority_queue容器
  6. 通过DeveloperApi获取spark程序执行进度及异常
  7. 程序员取悦女朋友的正确姿势---Tips(iOS美容篇)
  8. php之上传小案例,根据时间:月日分创建目录并随机生成文件名
  9. SCU 4436 Easy Math 2015年四川省赛题
  10. 《Programming WPF》翻译 第5章 4.元素类型样式
  11. 门面(Facade)模式
  12. ubuntu配置服务器apache
  13. VxWorks 任务
  14. 如何导入python中的模块
  15. scrapy模拟用户登录
  16. 查找二叉树(tree_a)
  17. gentoo ebuild 私人portage
  18. CF 633 F. The Chocolate Spree 树形dp
  19. 在不安装oracle客户端的情况下,使用PLSQL
  20. 【CF913F】Strongly Connected Tournament 概率神题

热门文章

  1. jquery.validate验证,jquery.Form插件提交,主要可以异步提交文件
  2. STM32的System memory
  3. elasticsearch安装中文分词器
  4. 跟浩哥学自动化测试Selenium -- 我的第一个Demo (2)
  5. java 实现redis缓存
  6. 天平 (Not so Mobile UVA - 839)
  7. 关于Python3中函数:
  8. 深入理解 Vuejs 动画效果
  9. 有个AI陪你一起写代码,是种怎样的体验?| 附ICLR论文
  10. Juice账号