bzoj1930
1930: [Shoi2003]pacman 吃豆豆
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1923 Solved: 435
[Submit][Status][Discuss]
Description
两个PACMAN吃豆豆。一开始的时候,PACMAN都在坐标原点的左下方,豆豆都在右上方。PACMAN走到豆豆处就会吃掉它。PACMAN行走的路线很奇怪,只能向右走或者向上走,他们行走的路线不可以相交。 请你帮这两个PACMAN计算一下,他们俩加起来最多能吃掉多少豆豆。
Input
第一行为一个整数N,表示豆豆的数目。 接下来 N 行,每行一对正整数,表示第i个豆豆的坐标。任意两个豆豆的坐标都不会重合。
Output
仅有一行包含一个整数,即两个PACMAN加起来最多能吃掉的豆豆数量
Sample Input
8
8 1
1 5
5 7
2 2
7 8
4 6
3 3
6 4
8 1
1 5
5 7
2 2
7 8
4 6
3 3
6 4
Sample Output
7
HINT
N < = 2000
Source
666 卡内存,zky大神只用了2000kb
很容易想出这是个最大费用流。但是很明显,2000*2000的边很容易tle,那么我们要进行剪枝。如果a->b,b->c,那么a->c是没有必要的。
但是还卡空间,因此我们可以用short。。。 连边:s:原点 ss:原点拆开的点,t:汇点
link(s,ss,f=2,c=0) for each i link(ss,i,f=2,c=0) link(i+n(拆点),t,f=2,c=0)
每个点和可以到达的点:link(i+n,j,f=1,c=1) link(i+n,j,f=1,c=1) 并且我们先按x排序,从x小到大枚举,如果当前的y比之前最小值要大,那么肯定之前连过,不用连了。
#include<bits/stdc++.h> using namespace std; #define inf (1<<30) #define N 2010 struct edge { short f,c,to; int nxt; }e[4500010]; struct data { int x,y; }x[4010]; int cnt=1,s,t,ss,n; int pree[4010],prev[4010],dist[4010],head[4010]; short q[4200010]; inline bool cp(data x,data y) { if(x.x!=y.x) return x.x<y.x; return x.y<y.y; } inline int min(int x,int y) { return x<y?x:y; } inline void link(int u,int v,int f,int c) { e[++cnt].nxt=head[u]; head[u]=cnt; e[cnt].to=v; e[cnt].f=f; e[cnt].c=c; } inline void ins(int u,int v,int c,int f) { link(u,v,f,c); link(v,u,0,-c); } inline bool spfa() { memset(dist,-1,sizeof(dist)); int l=1,r=0; q[++r]=s; dist[s]=0; while(l<=r) { int u=q[l++]; for(int i=head[u];i;i=e[i].nxt) if(e[i].f&&dist[e[i].to]<dist[u]+e[i].c) { prev[e[i].to]=u; pree[e[i].to]=i; dist[e[i].to]=dist[u]+e[i].c; q[++r]=e[i].to; } } return dist[t]!=-1; } inline int flow() { int u=t,delta=inf; while(u!=s) { delta=min(delta,e[pree[u]].f); u=prev[u]; } u=t; while(u!=s) { e[pree[u]].f-=delta; e[pree[u]^1].f+=delta; u=prev[u]; } return dist[t]*delta; } inline void MinCostFlow() { int ans=0,cur=0; while(spfa()) { cur+=flow(); if(cur>ans) ans=cur; } printf("%d\n",ans); } int main() { scanf("%d",&n); s=2*n+1; t=2*n+2; ss=s+2; for(int i=1;i<=n;i++) scanf("%d%d",&x[i].x,&x[i].y); ins(s,ss,0,2); for(int i=1;i<=n;i++) { ins(ss,i,0,2); ins(i+n,t,0,2); } sort(x+1,x+n+1,cp); for(int i=1;i<=n;i++) { ins(i,i+n,1,1); ins(i,i+n,0,1); int top=inf; for(int j=i+1;j<=n;j++) if(x[j].y<top&&x[i].y<=x[j].y) ins(i+n,j,0,2),top=x[j].y; } MinCostFlow(); return 0; }