【BZOJ1930】【SHOI2003】吃豆豆

初见杀……

原题:

两个PACMAN吃豆豆。一开始的时候,PACMAN都在坐标原点的左下方,豆豆都在右上方。PACMAN走到豆豆处就会吃掉它。PACMAN行走的路线很奇怪,只能向右走或者向上走,他们行走的路线不可以相交。 请你帮这两个PACMAN计算一下,他们俩加起来最多能吃掉多少豆豆。

N < = 2000

一眼秒掉,拆点费用流

然后发现内存64M???减少边的数组,提交,RE……

看chty的题解,更换建图方式,减少边数,提交,WA……

然后我的上午没了

解题思路很简单,拆点费用流即可,关键就在减少边数上

先按x第一优先级y第二优先级升序排序,然后对于每个点i从i+1往后扫,同时记录一个max(初值为oo),对于某个扫到的点j,如果a[j]>=a[i]且a[j]<max,就连边并max=a[j]

然后对于每个拆开的点中间连费用为1的边基础上再连费用为0的边,这样做是为了配合上面的建图方式使得前面的点能跳过这个点扫到后面的点

注意一定要连费用为0,否则后果就是直接被干掉一个上午/下午/晚上

主要原因还是因为看到这种建图方式后没有深刻理解就直接写上去了,导致最后没有连出费用为0的边

心好累,实在看不懂怎么建图就看代码把,注意不要忘了费用为0的边

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 #define ll long long
 8 const int oo=1000000000;
 9 ll rd(){ll z=0,mk=1;  char ch=getchar();
10     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)mk=-1;  ch=getchar();}
11     while(ch>=‘0‘&&ch<=‘9‘){z=(z<<3)+(z<<1)+ch-‘0‘;  ch=getchar();}
12     return z*mk;
13 }
14 struct dcd{ll x,y;}a[21000];
15 bool cmp(dcd x,dcd y){  return (x.x==y.x)?(x.y<y.y):(x.x<y.x);}
16 //bool cmp(dcd x,dcd y){  return x.x<y.x;}
17 struct ddd{int nxt,y,v,rvs,c;}e[810000];  int lk[4100],ltp=0;
18 inline void ist(int x,int y,int z,int _cst){
19     e[++ltp].nxt=lk[x],lk[x]=ltp,e[ltp].y=y,e[ltp].v=z,e[ltp].rvs=ltp+1,e[ltp].c=_cst;
20     e[++ltp].nxt=lk[y],lk[y]=ltp,e[ltp].y=x,e[ltp].v=0,e[ltp].rvs=ltp-1;e[ltp].c=-_cst;
21 }
22 int n;  int s,t,ss;
23 int lst[4100],lst_e[4100];
24 int dst[4100];
25 int q[810000],hd=0,tl=0,qt=800000;  bool vstd[4100];
26 bool spfa(){
27     memset(dst,-1,sizeof(dst));
28     q[hd=1]=s;  tl=0;  vstd[s]=true;  dst[s]=0;
29     //for(int k=1;k<=hd;++k){
30     while(tl!=hd){
31         int k=tl=(tl==qt ? 1 : tl+1);
32         for(int i=lk[q[k]];i;i=e[i].nxt)
33             if(e[i].v && dst[q[k]]+e[i].c>dst[e[i].y]){
34                 dst[e[i].y]=dst[q[k]]+e[i].c;
35                 lst[e[i].y]=q[k],lst_e[e[i].y]=i;
36                 if(!vstd[e[i].y])  q[hd=(hd==qt ? 1 : hd+1)]=e[i].y,vstd[e[i].y]=true;
37             }
38         vstd[q[k]]=false;
39     }
40     return dst[t]>0;
41 }
42 int cstflw(){
43     int bwl=0,mnflw=oo;
44     while(spfa()){
45         mnflw=oo;
46         for(int i=t;i!=s;i=lst[i])  mnflw=min(mnflw,e[lst_e[i]].v);
47         for(int i=t;i!=s;i=lst[i]){
48             bwl+=mnflw*e[lst_e[i]].c;
49             //cout<<lst[i]<<" "<<i<<" "<<e[lst_e[i]].c<<endl;
50             e[lst_e[i]].v-=mnflw,e[e[lst_e[i]].rvs].v+=mnflw;
51         }
52     }
53     return bwl;
54 }
55 int main(){//freopen("ddd.in","r",stdin);
56     //freopen("ddd.out","w",stdout);
57     memset(vstd,0,sizeof(vstd));
58     cin>>n;  s=0,t=n+n+1,ss=t+1;
59     for(int i=1;i<=n;++i)  a[i].x=rd(),a[i].y=rd();
60     sort(a+1,a+n+1,cmp);
61     //for(int i=1;i<=n;++i)  cout<<a[i].x<<" "<<a[i].y<<endl;
62     for(int i=1;i<=n;++i){
63         int mx=oo;
64         for(int j=i+1;j<=n;++j)
65             if(a[j].y>=a[i].y && a[j].y<=mx)  ist(i+n,j,oo,0),mx=a[j].y;
66             //if(a[j].y>=a[i].y && a[j].x>=a[i].x)  ist(i+n,j,oo,0);
67         ist(ss,i,oo,0),ist(i+n,t,oo,0),ist(i,i+n,1,1),ist(i,i+n,1,0);
68     }
69     ist(s,ss,2,0);
70     cout<<cstflw()<<endl;
71     return 0;
72 }

时间: 2024-10-08 11:13:01

【BZOJ1930】【SHOI2003】吃豆豆的相关文章

P4066 [SHOI2003]吃豆豆

我和这道题的邂逅,是在那个曼妙的周五的夜晚. 作为一道模拟题,她很好地履行了她的职责,不让我会…… 言归正传… 其实在离模拟结束还有14分钟的时候我想出来了费用流的写法……(70分),但是显然我有一段时间没有写网络流了,再加上时间太短,就没有去写. 这道题和传纸条好像啊……我一开始考虑dp,但是范围太大了,没法下手……再转念一想——不就是这两条路径上的点最多嘛?而对于不能交叉,我们还能联想到网络流的流量限制. 于是——最大费用最大流. 对于一个点只能选一次的限制,都是网络流的常规套路了——拆点建

HTML5吃豆豆游戏开发实战(一)使用Canvas绘制游戏主角

最近在学习HTML5,爱因斯坦曾说过,"最好的学习就是自己去经历".于是,我想在学习HTML5的同时,做一款简单的小游戏,这样学习起来也会很有趣的,我想做的是以前小时候玩儿的小霸王上面的很经典的一款游戏,叫"吃豆豆",后面有怪物跟着跑,蛮好玩的,还很虐心,相信大家都玩儿过. 吃豆豆就是这款啦: 我就用前面学的一些HTML5的简单的一些知识来简单模拟这款游戏吧.我做这款游戏不打算用图片,全部用canvas来画,这样才有意思,嘿嘿. 正如大家所看到的,我们游戏的主角就是

BZOJ1930 [Shoi2003]pacman 吃豆豆

SHOI出过这么鬼的题?..跪 首先我们可以想到费用网络流,找一个流量为2的最大费用流即可,问题是怎么建图 因为针对点才有收益,而且收益只有一次,所以考虑拆点,不妨设一个点p拆成入点p1和出点p2 则p1 -> p2连边流量为1,费用为1:再连边流量为1,费用为0:S向p1连边流量为1,费用为0:p2向T连边,流量为1,费用为0 若p能到达q,则p2 -> q1连边,流量为2,费用为0 然后会发现边太多...优化? 如果i能到达j,j能到达k,则i不要向k连边,于是就是一个单调性的问题,对点按

BZOJ1930 [Shoi2003]pacman 吃豆豆 费用流

题目大意:在二维平面上有若干个点,求出两条不相交的二维LIS,使得上面包含的点的数目最多. 思路1:暴力建图 注意到不相交这个条件根本没用,画图可以发现如果相交的话,我们总可以通过交换一些点使得两个序列不相交. 那么问题转化为求出两个没有公共点的上升子序列,使得长度之和最大. 对于这种情况我们利用最大费用流求解. 设(a,b)分别表示一条有向边的流量和费用. S->S' (2,0) S'->x(1,0),x'->T(1,0)(1<=x<=n) x->x' (1,1) 表

BZOJ 1930 Shoi2003 pacman 吃豆豆 费用流

题目大意:给定一个平面上的一些点,吃豆先生从原点出发,只能向右或向上走,求两个吃豆先生最多吃到多少豆 每个点拆成两个,之间连一条流量为1,费用为1的边: 如果从一个点出发可以到达另一个点,就将前一个点的出点连向后一个点的入点 跑费用流.但是这样显然是会TLE的 如果i能到j,j能到k,那么显然无需连i->k这条边 这是一个剪枝 加了这个剪枝之后可能会WA 因此还要考虑一个点经过多次的情况 即每个点从入点向出点再连一条流量为1,费用为0的边 加了这个之后就能过了 剪枝不强 但是没有什么情况能把这个

BZOJ 1930 SHOI 2003 pacman 吃豆豆 费用流

题目大意:给出一些平面上的点,你有两个吃豆人,从一个点出发,这个吃豆人可以吃到当前点右上方的点.问这两个吃豆人最多可以吃到多少豆子. 思路:我已經吧不相交的条件去掉了.. 不加优化的费用流模型很明显 超级源->源 flow2 cost0 汇->超级汇 flow2 cost0 下面是拆点 i << 1 -> i << 1|1 flow1 cost1 对于从点i能够到达点j的情况 i << 1|1 - > j << 1 flow1 cos

2014061404吃豆豆(C++)

#include<cstdio> #include<algorithm> #define N 10010 using namespace std; int n,i,j,rd[N],t,w,tot,id[N]; int dp,pre[3000000],p[N],tt[3000000],z[N],ID[N],tmp; int f[2500][2500]; struct g{ int x,y; }a[N]; bool cmp(g a,g b) { if (a.x==b.x) return

HTML5吃豆豆游戏开发实战(四)2d碰撞检测、重构-第二篇

今天下午在家没事,写代码.先总结一下学习HTML5和JS的一些经验,再来说游戏的事吧! 这完全是一个HTML5和JS的入门新手的见解,如果您和我一样是新手的话,欢迎交流,当然,高手如果不介意的话,帮小弟指点一二那就更好啦,谢谢,嘿嘿!入正题吧! 1.语法方面 1.1  JS关于数组的定义方法要注意: 比如:var walls = [new Wall(262,200,100,30),new Wall(662,60,30,400),new Wall(762,300,200,30)]; 这是定义一个墙

HTML5吃豆豆游戏开发实战(二)主角移动和动画循环设置

接着上一篇讲,在上一篇中呢,我已经使用Canvas绘制出了我们游戏的主角,姑且叫它"小嘴"吧,因为只有嘴巴,嘿嘿,我还添了眼睛. 在这一篇中呢,就实现物体的移动和动画播放(一直张开嘴吧关闭嘴巴的动画,很饥渴的样子). 1. 要做玩家和游戏的交互,当然要考虑--如何设置按键响应这个问题. 那么如何设置呢? 我们可以通过在body标签里面添加事件来响应用户的操作: 由于我们要用W,A,S,D来控制物体的上下移动,这是按键响应,于是我们选择用onkeydown事件. onkeydown 事件